最近打算寫一些前端知識的總結以及個人的見解,現在是第一篇,先寫一下關於HTTP相關的東西。
之前寫過一篇文章是關於curl命令與HTTP請求,裏面也提到一些關於HTTP的東西,這篇文章會再補充一下。
HTTP是什麼
HTTP即超文本傳輸協議(Hyper Text Transfer Protocol),是一個簡單的請求-響應協議,用於傳輸數據。
HTTP誕生之初主要是應用於WEB端內容獲取,隨着互聯網的發展,更多的內容開始被展示(更多的圖片文件),排版變得更精美(更多的CSS),更復雜的交互也被引入(更多的JS)。用户打開一個網站首頁所加載的數據總量和請求的個數也在不斷增加。所以HTTP也是在不斷進化中。
一個完整的HTTP請求體可以參閲之前的文章 《curl命令與HTTP請求》。
HTTP常見的請求方法、狀態消息以及頭(headers)
請求方法
GET 方法
GET 是最常用的 HTTP 請求方法,會顯示請求指定的資源,並返回響應主體,一般對它的期望是安全且冪等的(指對同一個 URL 的多個請求應該返回同樣的結果)。
所謂安全是指該操作用於獲取信息而非修改信息。換句話説,GET 請求一般不應產生副作用。就是説,它僅僅是獲取資源信息,就像數據庫查詢一樣,不會修改和增加數據,不會影響資源的狀態。
POST 方法
POST 方法用於向指定資源提交數據,請求服務器進行處理(例如提交表單或者上傳文件),數據被包含在請求本文中。
POST 請求可能會創建新的資源或修改現有資源,或二者皆有。每次提交,表單的數據被瀏覽器用編碼到HTTP請求的body裏。
瀏覽器發出的POST請求的body的主要格式
- application/x-www-form-urlencoded 用來傳輸簡單的數據,如 "key1=value1&key2=value2" 這樣的格式。
- multipart/form-data 主要用來傳輸文件內容。
- application/json 告訴服務端消息主體是序列化後的 JSON 字符串。
- text/plain 純文本格式
下圖是關於GET和POST的區別
HEAD 方法
與 GET 方法一樣,都是向服務器發出指定資源的請求,只不過服務器將不傳回資源的本文部分,只返回頭部消息。
它的好處在於,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲取其中“關於該資源的信息”(元信息或稱元數據),對資源的首部進行檢查,比如:
- 如果 GET /users 返回用户列表,
- 那麼 HEAD /users 將發出相同的請求,但不會返回用户列表。
HEAD 方法的使用場景
- 在不獲取資源的情況下,瞭解資源的一些信息,比如資源類型;
- 通過查看響應中的狀態碼,可以確定資源是否存在;
- 通過查看首部,測試資源是否被修改。
PUT 方法
PUT 方法用於將數據發送到服務器來創建/更新資源。
PUT 與 POST 方法的區別在於,PUT 方法是冪等的:調用一次與連續調用多次是等價的(即沒有副作用),而連續調用多次 POST 方法可能會有副作用,比如將一個訂單重複提交多次。
DELETE 方法
DELETE 方法就是請求服務器刪除指定 URL 所對應的資源。但是,客户端無法保證刪除操作一定會被執行,因為 HTTP 規範允許服務器在不通知客户端的情況下撤銷請求。
OPTIONS 方法
OPTIONS 方法用於獲取目的資源所支持的通信選項。
客户端可以對特定的 URL 使用 OPTIONS 方法,也可以對整站(通過將 URL 設置為“*”)使用該方法。
若請求成功,則它會在 HTTP 頭中包含一個名為 “Allow” 的頭,值是所支持的方法,如 “GET, POST”。
使用示例
可以使用 OPTIONS 方法對服務器發起請求,以檢測服務器支持哪些 HTTP 方法,響應報文包含一個 Allow 首部字段,該字段的值表明了服務器支持的所有 HTTP 方法:
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
個人見解
其實無論什麼請求方法,請求的數據都可以選擇放在URL或者body中。不存在GET請求的數據只能在放在URL,POST的請求只能放在body的説法。只是當GET請求時,數據放在body會被忽略或者警告。而當POST請求時,數據也可以放在URL上,此時後端獲取數據的方法應該使用getQueryString的方法,但是這樣就違背了POST請求的初衷,所以使用POST請求的時候,還是儘量將數據放在body上。
常見的狀態消息(狀態碼)
2xx:成功
200 OK - 請求成功
3xx:重定向
302 Found - 所請求的頁面已經臨時轉移至新的url。
304 Not Modified - 未按預期修改文檔。客户端有緩衝的文檔併發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客户只想比指定日期更新的文檔)。服務器告訴客户,原來緩存的文檔還可以繼續使用。
4xx:客户端錯誤
400 Bad Request - 錯誤請求,客户端請求有語法錯誤,不能被服務器所理解。
401 Unauthorized - 未授權,客户端的請求需要身份驗證,服務器驗證未通過。
403 Forbidden - 對被請求頁面的訪問被禁止
404 Not Found - 服務器無法找到被請求的頁面
405 Method Not Allowed - 請求中指定的方法不被允許
5xx:服務器錯誤
500 Internal Server Error - 請求未完成,服務器遇到不可預知的情況
501 Not Implemented - 請求未完成,服務器不支持所請求的功能
502 Bad Gateway - 請求未完成,服務器從上游服務器收到一個無效的響應
503 Service Unavailable - 請求未完成,服務器臨時過載或宕機
504 Gateway Timeout - 網關超時
常見的 HEADERS
請求頭 Request Header
| 字段名 | 説明 |
|---|---|
| Accept | 用户代理可處理的媒體類型,表示客户端希望接收的數據類型 |
| Accept-Charset | 優先的字符集 |
| Accept-Encoding | 優先的內容編碼 |
| Host | 指定資源所在服務器 |
| Referer | 告訴服務器該網頁是從哪個頁面鏈接過來 |
| If-Match | 比較實體標記(ETag) |
| If-Modified-Since | 比較資源的更新時間 |
| If-None-Match | 比較實體標記(與If-Match相反) |
響應頭 Response Header
| 字段名 | 説明 |
|---|---|
| ETag | 資源的匹配信息 |
| Location | 令客户端重定向至指定URI |
| Server | 包含有關原始服務器用來處理請求的軟件的信息 |
| Last-Modified | 資源修改的日期及時間 |
| Access-Control-Allow-Methods | 明確客户端所要訪問的資源允許使用的方法或方法列表 |
除此之外,也有一些通用頭可用於請求或響應
| 字段名 | 説明 |
|---|---|
| Content-Type | 實體頭部用於指示資源的 MIME 類型(media type)。 |
| Content-Encoding | 實體主體適用的編碼方式 |
| Content-Length | 實體主體的大小(字節) |
更多 HTTP Header 信息可參考 MDN HTTP 文檔
瀏覽器緩存機制介紹
總的來説,可以分為三種驗證機制來實現緩存:
- 設置資源有效時間
- 比較資源的最新修改時間
- 比較資源的唯一標識(ETag,類似版本號,當資源發生改變的時候標識會隨之改變)
設置資源有效時間
當客户端第一次請求完成的時候,服務端會在響應頭加上 Cache-Control 或 Expires 字段,用來表示該資源的有效時間。
當瀏覽器第二次發送請求時,會先根據該字段進行驗證,如在有效時間內,則直接使用資源副本。
注意:Expires 是 HTTP 1.0 的字段,而 Cache-Control 是 HTTP 1.1 的字段,當 Expires 與 Cache-Control 同時存在時,Cache-Control 的優先級要高於 Expires。所以可以忽略上面提到的 Expires。因為 Cache-Control 相對於 Expires 更加具體,細緻。參見 Cache-Control文檔
比較資源的最新修改時間
該方法主要是利用 Last-Modified 和 If-Modified-Since 配合完成:
當客户端第一次請求完成的時候,服務端會在響應頭加上 Last-Modified 字段,用來表示該資源的最新修改時間。
當瀏覽器第二次發送請求時,會在請求頭的 If-Modified-Since 字段加上上次請求返回的 Last-Modified 時間。HTTP 服務器收到該時間後,會對該資源的修改時間進行對比,如最新修改時間一致,則證明該資源無更新,然後響應 304 告訴客户端可直接使用瀏覽器資源副本。若最新修改時間不一致,服務器則響應 200,並向客户端發送新的資源。
比較資源的唯一標識
此方法與比較資源的最新修改時間類似,主要是利用 If-None-Match 和 ETag 配合完成:
當客户端第一次請求完成的時候,服務端會在響應頭加上 Etag 字段,用來表示該資源的唯一標識。
當瀏覽器第二次發送請求時,會在請求頭的 If-None-Match 字段加上上次請求返回的 ETag 標識。HTTP 服務器收到該標識後,會對該資源的標識進行對比,如一致,則證明該資源無更新,然後響應 304 告訴客户端可直接使用瀏覽器資源副本。若不一致,服務器則響應 200,並向客户端發送新的資源。
下面用一張流程圖來完整説明當瀏覽器發起 HTTP 請求時緩存機制的過程:
Etag相對於Last-Modified的優勢:
- Last-Modified標註的最後修改只能精確到秒級,如果某些文件在1秒鐘以內,被修改多次的話,它將不能準確標註文件的修改時間;
- 如果某些文件會被定期生成,當有時內容並沒有任何變化,但Last-Modified卻改變了,導致文件沒法使用緩存;
- 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形。
Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,所以能夠更加準確的控制緩存。
最後,雖然説瀏覽器緩存對用户體驗有極大的好處,但是作為開發者,我們在開發的時候則需要禁止這「討厭」瀏覽器緩存,方法是打開瀏覽器的開發者工具,在 Network 中有個 Disable cache ,鈎上就可以了,鈎上後瀏覽器會忽略掉文檔過期驗證和服務器再驗證的過程,直接向服務器請求最新的資源。