Contents

沒有資源卻還有頁面?HTTP 404 的解析與應用

本篇文章會簡單說明,為何我們連到不存在的頁面時,Server為何會給我們一個 404 的網頁?另外也會簡單說明設定的方式。

前言

用 Hugo 建置 blog 時,發現有一個 404.html,後續使用時發現,當我連接到不存在的網頁時,一律都會跳轉到我建立的 404.html,雖然以前有注意到這件事,但因為最近忙到沒時間閱讀新的技術,想說本次以此為主題來寫筆記。

What is 404?

在提到 404 之前,我們先來看我覺得是status code聖經本的連結 :
HTTP response status codes

然後把 404 找出來吧(Ctrl + F)

404 Not Found
The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web.

簡單來說就是找不到你要的東西啦。
好比你給我一間很好吃的牛肉麵店的地址,我依據你給的地址去到目的地時,發現該牛肉麵店已經關了(或是換地方開店,現在店租貴得要命),這時候我就會跟你說

欸,沒有這家店阿!

404 Not Found 應該也像這個意思。

404.html

好,那明明就沒有找到資源,為甚麼我連到不存在的資源時,又會給我一個自定義的 404.html 呢?

在伺服器端,我們可以在傳送 status code 404 後,透過 rewrite 的方式緊接著傳送 404.html,合併在同一個 response 中,這個 404.html 讓使用者不會只看到一個由 browser 產生的頁面,而是自己定義的頁面,這個頁面就可以加入許多自己想放的內容,站台的 Logo,sitemap 與廣告等。

下面是 curl 的結果,你可以發現雖然給我 status code 404,但後續有給我 404.html 的內容。

$ curl https://ekoismylove.github.io/test.html
HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Length: 2332
Server: GitHub.com
Content-Type: text/html; charset=utf-8
permissions-policy: interest-cohort=()
Access-Control-Allow-Origin: *
Strict-Transport-Security: max-age=31556952
ETag: W/"652d3b5a-1c9a"
Content-Encoding: gzip
x-proxy-cache: MISS
X-GitHub-Request-Id: 599C:57EC:24D998A:3342522:653F9743
Accept-Ranges: bytes
Date: Mon, 30 Oct 2023 11:45:07 GMT
Via: 1.1 varnish
Age: 0
X-Served-By: cache-ewr18167-EWR
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1698666308.830006,VS0,VE22
Vary: Accept-Encoding
X-Fastly-Request-ID: c9219940daf0e76b1973ff262dd5712fd3b0576d

<!doctype html><html lang=zh-tw>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta name=robots content="noodp">
<meta http-equiv=x-ua-compatible content="IE=edge, chrome=1">
<title>404 Page not found - Wei's Note</title><meta name=Description content><meta name=keywords content="go,ansible,infra,linux,blog"><meta property="og:title" content="404 Page not found">
以下被小精靈吃掉了 ... 030

Soft 404

有些站台在找不到資源時,會使用 200 OK 並加入 404.html 合併為一個 response 給 Client。

明明就沒有該資源,還回覆 200 OK?

我們稱這個為 Soft 404(軟 404),因為這樣做並不是不對,我的站台正確的給了 404.html,故回覆 200 OK 很正常吧 !
但是這樣做會有些缺點 :

  1. 會降低 Google Search 的排名。
  2. 提高故障排除的難度,因為正常跟錯誤的 status code 都是 200 OK。

rewrite ? redirect ?

至於要如何在使用者連接到不存在的資源時,給予自定義的 404.html 呢?
前面提到使用 rewrite 的方式,由伺服器端來處理這個要求,給予另一個資源,也就是我們自定義的 404.html

redirect 也可以做到吧?

沒錯,透過 redirect 的方式也可以實現,但兩者是有不同的地方。

Rewrite

  1. 由Server處理,直接在Server內部修改URL。
  2. 通常用來做簡單化URL,例如我原本的URL是ekoismylove.github.io/post/test/test/test/404.html,但我可以讓Client看到的是 ekoismylove.github.io/404.html

Redirect

  1. 通常用來給 Client 新的 URL 後,由Client處理,用來要求新的資源。
  2. 用 redirect 的 status code 通常會是 301 Moved Permanently或是302 Found,browser會再根據這些response去重新發出新的 request。通常會是新的 URL。(e.g. ekoismylovetest.github.io -> ekoismylove.github.io)

簡單來說,rewrite是Server處理,redirect是Client處理。

Setting for Server

那要怎麼設定呢? 我的blog是在Github Pages上,Github已經幫我處理好這件事情,另外在 GitLab Pages and Cloudflare Pages也已經做好了

Apache

我們可以透過新增 .htaccess,在內部加入 ErrorDocument 404 /404.html 的方式,透過這個Setting讓apache實現這個功能,白話一點就是404錯誤時,要給甚麼404錯誤資源,當然不只404,其他的 status code 也可以用這個方式修改。

Nginx

我們可以在 nginx.conf內,加入 error_page 404 /404.html,其實跟Apache是類似的。

結論

在瀏覽網頁時,最常看到的就是 status code 404,現今有許多網站開發者都會設計 404.html,並透過相關的設定,用來給使用者較好的體驗。

當然,最好是能快速且穩定給使用者正確的資源,因此日常的維護非常重要,畢竟使用者看到再華麗的 404.html 可能也不會開心,畢竟這不是使用者想要的資源。

參考資料

  1. HTTP response status codes
  2. Custom 404 page