大家好,我是 Yubin
本篇文章會介紹 HTTP Header 的基本知識,以及透過 Fastify 要如何控制 HTTP Header。
當我們定義了一個像這個 route 之後
server.get('/', async (request, reply) => {
return reply.status(200).send({
message: 'Hello World'
})
})
把 app 跑起來,假設開在本機的 8888 port 上,用瀏覽器打開 localhost:8888/
,
可以看到 {"message":"Hello World"}
的訊息。
為什麼我們會看到這樣的訊息呢?
我們只是在瀏覽器的網址列,敲入一串文字,就可以看到訊息,為什麼。
在 Web 的世界,HTTP 是一個常見的通訊協定,我們可以基於這個協定跟別人要求東西,如果別人願意回應你,你就可以透過這個協定收到東西。
由於一般人要自己處理 HTTP 這個通訊協定非常麻煩,因此我們藉由一個代理工具 (User Agent) 來幫我們操作 HTTP Protocol,這個工具就是我們熟悉的瀏覽器。
HTTP 這個通訊協定定義了一些欄位,請求方可以在這些欄位上描述自己的要求 (request),發送給別人。別人收到後,只要照著 HTTP 協定定義的格式做回覆,就可以讓對方收到回應 (response)。
我們打開瀏覽器的開發者工具 (大部分瀏覽器是按 F12
),來觀察一下 HTTP Header。
可以明確看到的是,所謂的 HTTP Header,本質上就是一些文字。
GET / HTTP/1.1
,第一行描述了這個 request 使用的 HTTP Method,這邊採用的是 GET
。/
表示要拿的目標資源位置,HTTP/1.1
是採用的 HTTP 協定版本。
Host: localhost:8888
,表示目標主機的位址。
瀏覽器發出請求後,會將 domain name 轉換成 ip address,這之間的轉換可能是查主機上的對應表,或去跟 DNS 伺服器做詢問。
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0
這邊表示了這個 agent 的版本,目前我用的是 Linux 上的 Firefox。這個欄位的資訊在一些行銷、分析工具 (像 Google Analytics) 常常會被蒐集起來做分析,但這不可靠,可以自己隨便改。
Connection: keep-alive
維持 transaction 的連線,可以減少 TCP 重新連線的次數。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
,表示此 request 接受哪些 response 的回應格式,此案例為任何格式的回應都接受。
HTTP/1.1 200 OK
,回應的 HTTP 版本為 1.1,狀態碼是 200
,狀態為 OK
。
content-type: application/json; charset=utf-8
,回應內容的格式為 json
,字元編碼為 utf-8
。
content-length: 25
,回應內容的長度 (大小) 為 25 bytes。
Date: Tue, 20 Sep 2022 14:07:21 GMT
,回應的時間。
可以看到,基本上這些 Headers 就是一些 Key-Value Pair。
HTTP 協定定義了一些方法,每個方法有其代表的含意,這邊整理一些常見的方法。
詳細參考 MDN: HTTP Method
我們透過瀏覽器的網址列,送出的請求,就是 GET
請求。
在 Fastify 的程式中,我們定義了有 GET /
這樣的 route,表示只要有一個 GET
方法而且目標是 /
的 request 進來,我就會去處理他,處理的方法是 async (request, reply) => { ... }
這個函式。
於是瀏覽器送出請求給 Fastify 後,Fastify 就會收到 request,根據定義的處理函式。
return reply.status(200).send({
message: 'Hello World'
})
reply.status(200)
會回應狀態碼 200
,.send()
定義要回應的 Payload,Fastify 會把物件轉換為 JSON 格式的字串,並設定 content-type: application/json
來做回應。
透過 reply.headers()
可以自行定義想要的 headers。要定義自己的 Header 也是可行的。
server.get('/', async (request, reply) => {
reply.headers({ 'Content-Type': 'text/html' })
return reply.status(200).send('Hello World')
})
Status Code,狀態碼是用來代表 HTTP 回應內容狀態的三位數數字。
一般我們耳熟能詳的可能會聽到 404 Not Found
或 200 OK
。
狀態碼很多,大致可以分成五類
代表請求已被接受,需要繼續處理 (Continue)。
代表請求成功 (Successfully)。
表示需要重新導向 (Redirect)。
表示用戶端的錯誤 (Client Error)。
表示伺服端的錯誤 (Server Error)。
每個狀態碼都有其不同含意,身為良好的後端開發者,我們要準確回應相應的狀態碼。
根據需要,可以透過 reply.status()
設定想要回應的狀態碼
server.get('/', async (request, reply) => {
return reply.status(404).send({
message: 'Hello World'
})
})
如上範例,雖然可以自由設定要回傳的狀態碼,但因為每個狀態碼都有其代表的含意,許多工具也對這些狀態碼有不同的預設動作。
例如說,許多工具或函示庫收到 4xx/5xx 的狀態碼,就會視為這個請求失敗了,即使伺服器端有回應正常的 Payload,也會當作這個動作沒有成功,而開始進行例外處理。
正確的使用狀態碼是非常重要的。