為什麼存取同一個網址卻返回不同的內容

2023-05-11 21:00:42

哈嘍大家好,我是鹹魚。今天給大家分享一個關於 HTTP 有趣的現象

連結:https://csvbase.com/meripaterson/stock-exchanges

我們用瀏覽器存取這個連結,可以看到下面的網頁

但如果我們使用 curl 命令去存取這個連結呢?

可以看到返回的是一個 csv 檔案

我們用 wget 命令下載下來看看

可以看到 text/csv 欄位,表示下載了一個 csv 格式的檔案

奇怪,同樣的 url ,為什麼瀏覽器返回的內容跟 curl、wget 命令返回的內容卻不一樣

內容協商

當 HTTP 使用者端去傳送響應給 HTTP 伺服器端的時候,響應裡面會包含響應頭(headers)

我們來看下 Google瀏覽器傳送的響應頭

我們著重注意一下響應頭裡的 accept 欄位

這個 accept 報頭是一個無序列表,它告訴了 HTTP 伺服器端應該返回什麼媒體型別(又稱內容型別或檔案格式)的內容給我

以上面 Google 瀏覽器的 accept 報頭為例:這段 accept 報頭表示該請求中瀏覽器可接受的媒體型別(或檔案格式)的偏好。從左到右,各型別的優先順序逐漸降低

  • text/html: 瀏覽器首選的媒體型別,即 HTML 文字。
  • application/xhtml+xml: 次選的媒體型別,即 XHTML 文字。
  • application/xml;q=0.9: 伺服器可以傳送的 XML 型別的文字,但是使用者端更願意接收前面的兩種媒體型別,所以權重為 0.9。
  • image/avif,image/webp,image/apng: 瀏覽器能夠接受的圖片型別,優先順序逐漸降低。如果伺服器返回多種可接受的圖片型別,則瀏覽器將選擇優先順序最高的那個。
  • */*;q=0.8: 如果伺服器無法以以上任何一種型別響應,則瀏覽器願意接受任何型別,但是這個型別的優先順序最低,只有 0.8。
  • application/signed-exchange;v=b3;q=0.7: 該媒體型別是用於實現 Web 頁面「前進」和「後退」功能的標準。使用者端更願意接受前面提到的其他媒體型別,所以該型別的權重為 0.7。

所以說我們用 Google 瀏覽器去存取這個 url (csvbase.com)時,會跟 HTTP 伺服器端去協商:你應該返回什麼型別的內容給我,優先是 text/html

而 curl 命令或者 wget 命令去存取請求這個 url 時,預設情況下傳送的請求頭中的 Accept 欄位的值是 */*,表示支援接受所有型別的響應

而這個網站 csvbase 預設格式是 csv,所以說當 curl 命令或者 wget 命令去存取請求這個 url 時,得到的是一個 csv 格式返回內容

這就是 HTTP 協定中的內容協商(content negotiation)

HTTP內容協商是指使用者端和伺服器端協商出最適合的響應資料格式、語言等內容的過

HTTP中的內容協商機制,可以確保使用者端和伺服器端傳送和接收的內容格式是一致的,從而提高通訊的效率和可靠性

HTTP內容協商通常有三種型別:

  • 基於請求頭的內容協商(Header-based content negotiation)
  • 基於URL的內容協商(URL-based content negotiation)
  • 基於實體的內容協商(Entity-based content negotiation)

基於請求頭的內容協商是指使用者端在請求頭中指定自己可以接受的內容型別(MIME型別),伺服器根據使用者端的請求頭中所指定的資訊,選擇最合適的響應內容型別進行響應

常用的請求頭欄位是 Accept 和 Accept-Language。伺服器端根據 Accept 欄位的內容,選擇最匹配的響應型別進行響應

如果使用者端所能接受的響應型別都不能滿足伺服器端的響應型別,則會返回一個 406 Not Acceptable 的錯誤狀態碼

那有小夥伴可能會想:我用 curl 命令或者 wget 命令不想得到一個 csv 格式的響應,我想 HTTP 伺服器端返回其他型別的響應,這時候該怎麼辦

我們可以手動修改請求頭來告訴 HTTP 伺服器端它可以接受的媒體型別(即檔案格式)的偏好

參考文章:

How does it know I want csv? ⁠— An HTTP trick (csvbase.com)