HTTP之200還是304?
當瀏覽器第一次加載資源的時候,返回一般為200,意思是成功獲取資源,并會在瀏覽器的緩存中記錄下max-age,第二次訪問的時候:如果只是用瀏覽器打開,那么瀏覽器會去判斷這個資源在緩存里有沒有,如果有的話,會去判斷max-age,看看過期沒有,如果沒有過期,則直接讀緩存,根本不會和服務器進行交互,換句話說,斷網(wǎng)都能打開,就和本地跑一樣!如果已經(jīng)過期了,那就去服務器請求,等待服務器響應,這是很費時間的,服務器如果發(fā)現(xiàn)資源沒有改變過,那么就會返回304,告訴瀏覽器,我沒變過,你去讀緩存吧,于是瀏覽器也不用從服務器拉數(shù)據(jù)了,然而,等待服務器響應也是一個很要命的問題,在網(wǎng)速發(fā)達的今天,等一個響應,有時比下載還慢。如果是用瀏覽器刷新的,那么瀏覽器不會去判斷max-age了,直接去服務器拿,如果服務器判斷資源沒變過,則還是會返回304,和上面是一樣的,所以刷新一下,其實很可怕,等于把所有的資源都要去服務器請求一邊,問問服務器我過期了沒有。
瀏覽器在第一次請求資源的時候,服務端響應頭里可以設置expires字段,該字段表示該資源的緩存過期時間,第二次請求的時候,如果時間還在該緩存時間之內,則會直接使用緩存,否則重新加載資源, 這個expires字段有個缺陷,就是它必須服務端和客戶端的時間嚴格同步才能生效,所以現(xiàn)在很多人不會使用改方案。另外一種方案是第一次請求資源的時候,服務端設置響應頭cache-control: max-age,這樣設置的意思是告訴瀏覽器,這個資源什么時候過期,等第二次請求資源的時候,判斷是否超出了過期時間,如果沒超出,直接使用緩存。
緩存狀態(tài)碼 200 OK (from cache) 與 304 Not Modified
- 200 OK (from cache) 是瀏覽器沒有跟服務器確認,直接用了瀏覽器緩存;
- 304 Not Modified 是瀏覽器和服務器多確認了一次緩存有效性,再用的緩存。
304 Not Modified:客戶端有緩沖的文件并發(fā)出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務器告訴客戶,原來緩沖的文檔還可以繼續(xù)使用。
304 Not Modified 比 200 OK (from cache) 慢,指的是瀏覽器還向服務器確認了下 “If-Not-Modified”,才用的緩存
200和304特點
- 狀態(tài)碼200:請求已成功,請求所希望的響應頭或數(shù)據(jù)體將隨此響應返回。即返回的數(shù)據(jù)為全量的數(shù)據(jù),如果文件不通過GZIP壓縮的話,文件是多大,則要有多大傳輸量。
- 狀態(tài)碼304:如果客戶端發(fā)送了一個帶條件的 GET 請求且該請求已被允許,而文檔的內容(自上次訪問以來或者根據(jù)請求的條件)并沒有改變,則服務器應當返回這個狀態(tài)碼。即客戶端和服務器端只需要傳輸很少的數(shù)據(jù)量來做文件的校驗,如果文件沒有修改過,則不需要返回全量的數(shù)據(jù)。
狀態(tài)為304的請求要比狀態(tài)為200的請求的數(shù)據(jù)量小很多,因為304只需要返回響應頭,并不需要返回整個文件,所以只需要幾字節(jié)就可以了,這樣能夠節(jié)省大量的網(wǎng)絡帶寬,并減少了頁面的渲染時間。
什么是瀏覽器緩存?
瀏覽器緩存是為了節(jié)約網(wǎng)絡的資源加速瀏覽,瀏覽器在用戶磁盤上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁盤顯示文檔,這樣就可以加速頁面的閱覽。瀏覽器緩存主要包括強緩存和協(xié)商緩存。-- 百度百科
瀏覽器緩存也稱為http緩存。
通俗地說,瀏覽器緩存指的是瀏覽器為了節(jié)省網(wǎng)絡資源及加快頁面渲染,將請求過的資源緩存在本地(硬盤和內存中),再根據(jù)http響應頭來判斷是否讀取本地的緩存資源。
緩存HTTP頭信息
- Date:原服務器發(fā)送該資源響應報文的時間(GMT格式)
- Age:Age表示這個響應已經(jīng)存活了多久了(HTTP/1.0的響應不帶Age)
- Expires:即在 HTTP 頭中指明具體失效的時間(HTTP/1.0),Expires = HTTP-date
- Pragma:no-cache,每次請求頁面時都不要讀緩存,兼容HTTP/1.0,優(yōu)先級高于Expires(HTTP/1.0 + HTTP/1.1)
- Cache Control:優(yōu)先級高于Pragma、Expires(HTTP/1.1) 【public,客戶端和服務端都可以緩存;private,只能客戶端緩存;no-store,不使用緩存;no-cache,使用協(xié)商緩存?!?/li>
Expires
- Expires是http1.0提出的一個表示資源過期時間的header,它描述的是一個絕對時間,由服務器返回。
- Expires第二次請求時,將和本地時間比對。
- Expires 第一次請求服務器是,響應頭會返回一個Expires的文件過期時間。
- Expires 第二次請求,客戶端使用本地時間和文件的過期時間進行比對,如果文件未過期則直接使用本地緩存,返回狀態(tài)碼200(from memory cache)或200(from disk cache)。
Expires Cache-Control
- Cache-Control: no-cache 必須先與代理服務器確認是否更改,然后在在決定使用緩存還是請求,類似于協(xié)商緩存(304)
- Cache-Control: no-store 才是真正的不緩存數(shù)據(jù)到本地
- Cache-Control: public 可以被所有用戶緩存(多用戶共享),包括終端和CDN等中間代理服務器
- Cache-Control: private 只能被終端瀏覽器緩存(而且是私有緩存),不允許中繼緩存服務器進行緩存
- Cache-Control: must-revalidate如果緩存內容失效,請求必須發(fā)送服務器進行驗證
- Cache-Control: max-age=s 緩存內容在s秒后失效,僅HTTP1.1可用 max-gae 第一次請求服務器時,響應頭會返回一個 max-age,是文件多少時間后過期。max-gae 第二次請求,客戶端會校驗文件是否過期,如果文件未過期則直接使用本地緩存,返回狀態(tài)碼200(from memory cache)或200(from disk cache)。
強緩存(200 from disk cache 或者 200 from memory cache, 硬盤緩存和內存緩存)
強緩存指的是瀏覽器緩存了該請求的資源且根據(jù)緩存標識(響應頭的cache-control:max-age 及 expires)判定資源未過期。
協(xié)商緩存(304)
協(xié)商緩存指的是瀏覽器緩存了該請求的資源但未能判斷資源是否過期,需要向服務器發(fā)起攜帶緩存標識(響應頭的 last-modified 及 Etag)的請求來詢問資源是否過期。
瀏覽器緩存相關響應頭
強緩存相關
Expires
Expires 是 HTTP/1.0 中控制瀏覽器緩存的字段,其值為服務器返回的該請求結果緩存的到期時間。當瀏覽器再次發(fā)起請求時,如果客戶端時間早于到期時間,則直接讀取緩存結果而不用再次發(fā)起請求。
因為這邊用到了客戶端的時間進行判斷,所以可能會因為客戶端時間和服務器時間不同導致預期之外的緩存行為
Cache-Control
cache-control 是HTTP/1.1 的字段,是控制緩存的重要規(guī)則,它的值包含了幾組可選的值,中間使用逗號相隔開
- 控制代理服務器緩存
- public:所有內容被緩存(代理服務器和客戶端都可緩存)
- private(默認):僅客戶端可緩存
- 控制是否緩存
- no-cache:客戶端緩存內容,是否使用緩存需要與服務器進行協(xié)商
- no-store:所有內容不會被緩存
- 控制緩存有效期
- max-age:其值為資源的有效時間(秒),表示緩存將在xx秒后失效
當 max-age 和 expires 同時存在時,只有 max-age 有效,expires 將不再生效
協(xié)商緩存相關
last-modified
last-modified 用于標識資源的最新修改時間,用于標記內容是否更新。
響應頭的 last-modified 會作為緩存標識一起存儲與緩存中,當再次請求需要進行服務器協(xié)商時,請求頭的 if-Modified-Since 字段將帶上緩存中的 last-modified 的值與服務器的資源修改時間進行比較,判斷緩存是否過期。
使用 last-modified 有可能出現(xiàn)服務器資源未產生實質性更新但是修改時間更新的情況,比如資源重寫。
Etag
Etag 是服務器根據(jù)資源內容通過一系列算法計算得出的用于標識資源的字符串編碼,當資源內容有修改時,對應的 Etag 也會更新。其主要功能就是用于標記資源內容是否更新。
同樣的,響應頭的 Etag 會作為緩存標識一起存儲于緩存中,當再次請求需要進行服務器協(xié)商時,請求頭的 if-None-Match 字段將帶上緩存中的 etag 值與服務器上資源的 Etag 進行比較,判斷緩存是否過期。
當 Etag 和 last-modified 同時出現(xiàn)時,以 Etag 的標識為準。
瀏覽器緩存相關的請求頭
Cache-Control
- no-cache:強制向源服務器再次驗證,控制代理服務器不能直接返回緩存
- max-age:響應的最大age值,可以設置max-age=0使用協(xié)商緩存
last-modified-since
配合 last-modified 使用
if-None-Match
配置 Etag 使用
完整的瀏覽器緩存過程
- 判斷本地是否有緩存,如果本地沒有緩存資源則進入第4步,如果有則進入第2步。
- 通過 expires 和 max-age 判斷緩存是否過期,如果未過期則直接返回資源(200 from cache)。否則進入第3步。
- 攜帶緩存標識(if-modified-since if-None-Match)進行請求,與服務器協(xié)商驗證緩存是否過期,如果未過期則服務器返回不帶資源實體的響應,瀏覽器從緩存中獲取資源并返回給前端(304),否則進入第4步。
4.正常請求資源,服務器返回資源(200)并進行緩存。
緩存相關知識點
緩存的位置
瀏覽器緩存的存儲位置分為硬盤(disk cache)和內存(memory cache),瀏覽器的讀取順序為內存->硬盤。
不同的資源可能會緩存在不同的位置
- css:因為 css 解析構建 CSSOM 樹之后就不需要使用了,所以會被緩存在硬盤中,讀取時從硬盤讀取。
- JS 和圖片:因為瀏覽器解析JS和圖片之后,會將其放在內存中,所以優(yōu)先讀取內存(實踐證明并非一定),當打開新窗口或者瀏覽器時則讀取硬盤緩存。
不同的用戶行為導致的緩存問題
刷新(F5/Command+r)
刷新時會給文檔請求頭加上 Cache-Control:max-age=0,所以文檔一般會觸發(fā)協(xié)商緩存。而文檔之外的其他資源(JS css)則正常請求(可能會觸發(fā)強緩存或協(xié)商緩存)。
強制刷新(CTRL + F5/Command+shift+r/勾選disable cache)
強制刷新時會給請求頭加上 Cache-control:no-cache,使用協(xié)商緩存,但同時會刪除協(xié)商緩存字段(if-modified-since if-none-match),所以最終結果都是從服務器請求新資源。
關閉瀏覽器/打開新標簽
沒有特殊操作,有可能使用強緩存或協(xié)商緩存。