Http狀態碼
狀態碼 | 含義 |
---|---|
1XX | 請求正在被處理 |
2XX | 請求被成功處理 |
3XX | 請求需要附加操作,常見如重定向 |
4XX | 客戶端出錯導致請求無法被處理 |
5XX | 服務端處理出錯 |
2XX
狀態碼 | 原因短語 | 含義 |
---|---|---|
200 | OK | 請求被正常處理 |
204 | NO CONTENT | 請求成功,但是響應的報文中不含實體主體 |
206 | Partial Content | 只返回了請求資源的部分 |
204
: 例如option
請求,通常被用來做正式請求的預請求,這個請求只需要確認後續的請求能不能通過,即只需要一個結果,而不需要返回其他內容。
206
: 在 http的請求中,頭部添加Range
用來表示範圍請求,例如
'Range': byte=5001-10000 // 表示本次要請求資源的5001-10000字節的部分
這種情況下,如果服務器接受範圍請求並且成功處理,就會返回 206,並且在響應的頭部返回:
'Content-Range':bytes 5001-10000/10000// 表示整個資源有10000字節,本次返回的範圍爲 5001-10000字節
3XX
狀態碼 | 原因短語 | 含義 |
---|---|---|
301 | Moved Permanently | 資源被永久重定向了 |
302 | Found | 資源臨時重定向到location |
303 | See Other | 資源使用GET 訪問臨時重定向的location |
304 | Not Modified | 資源未改變,可直接使用緩存 |
307 | Temporary Redirect | 嚴格限制重定向不允許從POST 轉爲GET
|
301
與302
的唯一區別就在於一個是臨時,一個是永久。
4XX
狀態碼 | 原因短語 | 含義 |
---|---|---|
400 | Bad Request | 請求中有語法錯誤 |
401 | Unauthorized | 未經過認證 |
403 | Forbidden | 禁止訪問也就是無權限訪問 |
404 | Not Found | 服務端沒有找到所請求的資源 |
5XX
狀態碼 | 原因短語 | 含義 |
---|---|---|
500 | Internal Server Error | 服務器故障 |
503 | Service Unavailable | 服務器暫時無法使用 |
緩存機制
瀏覽器每次發起請求,都會先在瀏覽器緩存中查找該請求的結果以及緩存標識瀏覽器每次拿到返回的請求結果都會將該結果和緩存標識存入瀏覽器緩存中
強緩存
強緩存不會向服務器發送請求,直接從緩存中讀取資源,在 chrome 控制檯的 Network 選項中可以看到該請求返回200
的狀態碼,並且Size
顯示from disk cache
或from memory cache
。強緩存可以通過設置兩種 HTTPHeader 實現:Expires
和Cache-Control
。
1. Expires
緩存過期時間,用來指定資源到期的時間,是服務器端的具體的時間點。也就是說,Expires=max-age + 請求時間
,需要和Last-modified
結合使用。Expires 是 Web 服務器響應消息頭字段,在響應 http 請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數據,而無需再次請求。
Expires 是 HTTP/1 的產物,受限於本地時間,如果修改了本地時間,可能會造成緩存失效。Expires: Wed, 22 Oct 2018 08:41:00
GMT 表示資源會在Wed, 22 Oct 2018 08:41:00 GMT
後過期,需要再次請求。
2. Cache-Control
在 HTTP/1.1 中,Cache-Control
是最重要的規則,主要用於控制網頁緩存。比如當Cache-Control:max-age=300
時,則代表在這個請求正確返回時間(瀏覽器也會記錄下來)的 5 分鐘內再次加載資源,就會命中強緩存。Cache-Control
可以在請求頭或者響應頭中設置,並且可以組合使用多種指令:
指令 | 作用 |
---|---|
public | 響應可被客戶端和代理服務器緩存 |
private | 響應只可被客戶端緩存 |
max-age=30 | 緩存 30 秒後過期,需要重新請求 |
s-maxage=30 | 覆蓋max-age ,作用一樣,只是在代理服務器中生效 |
no-store | 不緩存任何響應 |
no-cache | 資源被緩存,但是立即失效,下次會發起請求驗證資源是否過期,配合協商緩存使用 |
max-stale=30 | 30 秒內,即使緩存過期也使用該緩存 |
min-fresh=30 | 希望在 30 秒內獲取最新的響應 |
詳細說明:
-
public
:所有內容都將被緩存(客戶端和代理服務器都可緩存)。具體來說響應可被任何中間節點緩存,如Browser
<--proxy1
<--proxy2
<--Server
,中間的proxy
可以緩存資源,比如下次再請求同一資源proxy1
直接把自己緩存的東西給Browser
而不再向proxy2
要。 -
private
:所有內容只有客戶端可以緩存,Cache-Control
的默認取值
。具體來說,表示中間節點不允許緩存,對於Browser
<--proxy1
<--proxy2
<--Server
,proxy
會老老實實把Server
返回的數據發送給proxy1
,自己不緩存任何數據。當下次Browser
再次請求時proxy
會做好請求轉發而不是自作主張給自己緩存的數據。 -
no-cache
:客戶端緩存內容,是否使用緩存則需要經過協商緩存來驗證決定。表示不使用Cache-Control
的緩存控制方式做前置驗證,而是使用Etag
或者Last-Modified
字段來控制緩存。需要注意的是,
no-cache
這個名字有一點誤導。設置了no-cache
之後,並不是說瀏覽器就不再緩存數據,只是瀏覽器在使用緩存數據時,需要先確認一下數據是否還跟服務器保持一致。 -
no-store
:所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存 -
max-age
:max-age=xxx
(xxx is numeric)表示緩存內容將在 xxx 秒後失效 -
s-maxage
(單位爲 s):同max-age
作用一樣,只在代理服務器中生效(比如 CDN 緩存)。比如當s-maxage=60
時,在這 60 秒中,即使更新了 CDN 的內容,瀏覽器也不會進行請求。max-age
用於普通緩存,而s-maxage
用於代理緩存。s-maxage
的優先級高於max-age
。如果存在 s-maxage,則會覆蓋掉max-age
和Expires
header。 -
max-stale
:能容忍的最大過期時間。max-stale
指令標示了客戶端願意接收一個已經過期了的響應。如果指定了max-stale
的值,則最大容忍時間爲對應的秒數。如果沒有指定,那麼說明瀏覽器願意接收任何 age 的響應(age 表示響應由源站生成或確認的時間與當前時間的差值)。 -
min-fresh
:能夠容忍的最小新鮮度。min-fresh
標示了客戶端不願意接受新鮮度不多於當前的 age 加上 min-fresh 設定的時間之和的響應。
3. Expires 和 Cache-Control 兩者對比
其實這兩者差別不大,區別就在於 Expires 是 http1.0 的產物,Cache-Control 是 http1.1 的產物,兩者同時存在的話,Cache-Control 優先級高於 Expires;在某些不支持 HTTP1.1 的環境下,Expires 就會發揮用處。所以 Expires 其實是過時的產物,現階段它的存在只是一種兼容性的寫法。
強緩存判斷是否緩存的依據來自於是否超出某個時間或者某個時間段,而不關心服務器端文件是否已經更新,這可能會導致加載文件不是服務器端最新的內容,那我們如何獲知服務器端內容是否已經發生了更新呢?此時我們需要用到協商緩存策略。
協商緩存
協商緩存就是強制緩存失效後,瀏覽器攜帶緩存標識向服務器發起請求,由服務器根據緩存標識決定是否使用緩存的過程,主要有以下兩種情況:
- 協商緩存生效,返回
304
和Not Modified
- 協商緩存失效,返回
200
和請求結果
協商緩存可以通過設置兩種 HTTP 頭Modified
和ETag
。
1. Last-Modified 和 If-Modified-Since
瀏覽器在第一次訪問資源時,服務器返回資源的同時,在 response header 中添加Last-Modified
的 header,值是這個資源在服務器上的最後修改時間,瀏覽器接收後緩存文件和 header;
Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
瀏覽器下一次請求這個資源,瀏覽器檢測到有Last-Modified
這個 header,於是添加If-Modified-Since
這個 header,值就是Last-Modified
中的值;服務器再次收到這個資源請求,會根據If-Modified-Since
中的值與服務器中這個資源的最後修改時間對比,如果沒有變化,返回 304 和空的響應體,直接從緩存讀取,如果If-Modified-Since
的時間小於服務器中這個資源的最後修改時間,說明文件有更新,於是返回新的資源文件和200
.
但是 Last-Modified 存在一些弊端:
如果本地打開緩存文件,即使沒有對文件進行修改,但還是會造成 Last-Modified 被修改,服務端不能命中緩存導致發送相同的資源.因爲 Last-Modified 只能以秒計時,如果在不可感知的時間內修改完成文件,那麼服務端會認爲資源還是命中了,不會返回正確的資源.既然根據文件修改時間來決定是否緩存尚有不足,能否可以直接根據文件內容是否修改來決定緩存策略?所以在 HTTP/1.1 出現了ETag
和If-None-Match
;
2. ETag 和 If-None-Match
Etag
是服務器響應請求時,返回當前資源文件的一個唯一標識(由服務器生成),只要資源有變化,Etag 就會重新生成。瀏覽器在下一次加載資源向服務器發送請求時,會將上一次返回的 Etag 值放到 request header 裏的If-None-Match
裏,服務器只需要比較客戶端傳來的 If-None-Match 跟自己服務器上該資源的 ETag 是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。如果服務器發現 ETag 匹配不上,那麼直接以常規GET 200
回包形式將新的資源(當然也包括了新的 ETag)發給客戶端;如果 ETag 是一致的,則直接返回304
知會客戶端直接使用本地緩存即可。
3. 兩者之間對比
- 首先在精確度上,Etag 要優於 Last-Modified。
Last-Modified 的時間單位是秒,如果某個文件在 1 秒內改變了多次,那麼他們的 Last-Modified 其實並沒有體現出來修改,但是 Etag 每次都會改變確保了精度;如果是負載均衡的服務器,各個服務器生成的 Last-Modified 也有可能不一致。
- 第二在性能上,Etag 要遜於 Last-Modified,畢竟 Last-Modified 只需要記錄時間,而 Etag 需要服務器通過算法來計算出一個 hash 值。
- 第三在優先級上,服務器校驗優先考慮 Etag。
強制緩存優先於協商緩存進行,若強制緩存(Expires 和 Cache-Control)生效則直接使用緩存,若不生效則進行協商緩存(Last-Modified / If-Modified-Since 和 Etag / If-None-Match),協商緩存由服務器決定是否使用緩存,若協商緩存失效,那麼代表該請求的緩存失效,返回 200,重新返回資源和緩存標識,再存入瀏覽器緩存中;生效則返回 304,繼續使用緩存。
實際場景應用緩存策略
1. 頻繁變動的資源
Cache-Control: no-cache
對於頻繁變動的資源,首先需要使用Cache-Control: no-cache
使瀏覽器每次都請求服務器,然後配合ETag
或者Last-Modified
來驗證資源是否有效。這樣的做法雖然不能節省請求數量,但是能顯著減少響應數據大小。
2. 不常變化的資源
Cache-Control: max-age=31536000
通常在處理這類資源時,給它們的Cache-Control
配置一個很大的max-age=31536000
(一年),這樣瀏覽器之後請求相同的 URL 會命中強制緩存。而爲了解決更新的問題,就需要在文件名(或者路徑)中添加 hash,版本號等動態字符,之後更改動態字符,從而達到更改引用 URL 的目的,讓之前的強制緩存失效(其實並未立即失效,只是不再使用了而已)。
內容參考:瀏覽器的緩存機制
Cookie的實現機制
Cookie是由客戶端保存的小型文本文件,其內容爲一系列的鍵值對。 Cookie是由HTTP服務器設置的,保存在瀏覽器中, 在用戶訪問其他頁面時,會在HTTP請求中附上該服務器之前設置的Cookie。
- 瀏覽器向某個URL發起HTTP請求(可以是任何請求,比如GET一個頁面、POST一個登錄表單等)
- 對應的服務器收到該HTTP請求,並計算應當返回給瀏覽器的HTTP響應。
- 在響應頭加入Set-Cookie字段,它的值是要設置的Cookie。
- 瀏覽器收到來自服務器的HTTP響應。
- 瀏覽器在響應頭中發現Set-Cookie字段,就會將該字段的值保存在內存或者硬盤中。
Set-Cookie字段的值可以是很多項Cookie,每一項都可以指定過期時間Expires。 默認的過期時間是用戶關閉瀏覽器時。
- 瀏覽器下次給該服務器發送HTTP請求時, 會將服務器設置的Cookie附加在HTTP請求的頭字段Cookie中。
瀏覽器可以存儲多個域名下的Cookie,但只發送當前請求的域名曾經指定的Cookie, 這個域名也可以在Set-Cookie字段中指定)。
- 服務器收到這個HTTP請求,發現請求頭中有Cookie字段, 便知道之前就和這個用戶打過交道了。
- 過期的Cookie會被瀏覽器刪除。
總之,服務器通過Set-Cookie響應頭字段來指示瀏覽器保存Cookie, 瀏覽器通過Cookie請求頭字段來告訴服務器之前的狀態。 Cookie中包含若干個鍵值對,每個鍵值對可以設置過期時間。