本文原鏈接:https://my.oschina.net/ososchina/blog/494074
https://blog.csdn.net/zl399615007/article/details/84534884
強制緩存(200)和協商緩存(304)整理
1、瀏覽器緩存
瀏覽器第一次打開一個網頁獲取資源后,根據返回的header信息來告訴如何緩存資源。
-
瀏覽器第一次請求:
-
瀏覽器后續請求時:
-
一.304靜態資源離線緩存
1)關於 Last-Modified
在瀏覽器第一次請求某一個URL時,服務器端的返回狀態會是200,資源響應頭有一個Last-Modified的屬性標記此文件在服務期端最后被修改的時間,另外一半也有個Etag,格式類似這樣:Last-Modified:Fri, 15 Feb 2013 03:06:18 GMT ETag:"be15b26c29bce1:0" #可選,這里為了准確確認資源是否變化
舉例:
客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送 If-Modified-Since和If-None-Match(可選報頭,值Etag的值) 報頭,詢問該時間之后文件是否有被修改過:
If-Modified-Since:Sat, 16 Feb 2013 07:30:07 GMT If-None-Match:"be15b26c29bce1:0" #可選,這里為了准確確認資源是否變化
舉例:
如果服務器端的資源沒有變化,則自動返回 HTTP 304 (Not Changed.)狀態碼,內容為空,否則重新發起請求,請求下載資源這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啟服務器時,則重新發出資源,返回和第一次請求時類似。從而保證不向客戶端重復發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。
2) 什么是”Etag”?
HTTP 協議規格說明定義ETag為“被請求變量的實體值” 。 另一種說法是,ETag是一個可以與Web資源關聯的記號(token)。典型的Web資源可以一個Web頁,但也可能是JSON或XML文檔。服務器單獨負責判斷記號是什么及其含義,並在HTTP響應頭中將其傳送到客戶端,以下是服務器端返回的格式:
ETag: "50b1c1d4f775c61:df3"
客戶端的查詢更新格式是這樣的:
If-None-Match: W/"50b1c1d4f775c61:df3"
如果ETag沒改變,則返回狀態304然后不返回,這也和Last-Modified一樣。本人測試Etag主要在斷點下載時比較有用。ETag出現的歷史原因是Last-Modified只做到了 “秒級別”的驗證,無法辨識毫秒,微妙級別的校驗,因此才出現了ETag。
ETag的出現,意味着客戶端需要需求的升級,因此If-None-Match,If-Match,If-Range隨之用來驗證文件變化。
3) Last-Modified和Etags如何幫助提高性能?
聰明的開發者會把Last-Modified 和ETags請求的http報頭一起使用,這樣可利用客戶端(例如瀏覽器)的緩存。因為服務器首先產生 Last-Modified/Etag標記,服務器可在稍后使用它來判斷頁面是否已經被修改。本質上,客戶端通過將該記號傳回服務器要求服務器驗證其(客戶端)緩存。
過程如下:-
客戶端請求一個頁面(A)。
-
服務器返回頁面A,並在給A加上一個Last-Modified/ETag。
-
客戶端展現該頁面,並將頁面連同Last-Modified/ETag一起緩存。
-
客戶再次請求頁面A,並將上次請求時服務器返回的Last-Modified/ETag一起傳遞給服務器。
-
服務器檢查該Last-Modified或ETag,並判斷出該頁面自上次客戶端請求之后還未被修改,直接返回響應304和一個空的響應體。
-
此外,如果緩存服務器版本,類型不同,建議使用Last-Modified,Etag可能造成緩存無法驗證的問題
二.緩存有效期期的實現(Cache-Control與Expires)
HTTP中,通過Cache-Control首部和Expires首部為文檔指定了過期時間,通過對過期時間的判斷,緩存就可以知道文檔是不是在保質期內。Expires首部和Cache-Control:max-age首部都是來告訴緩存文檔有沒有過期,為什么需要兩個響應首部來做這件簡單的事情了?其實這一切都是歷史原因,Expires首部是HTTP 1.0中提出來的,因為他使用的是絕對日期,如果服務端和客戶端時鍾不同步的話(實際上這種情況非常常見),緩存可能就會認為文檔已經過了保質期。
HTTP 1.1為了修正這個問題,引入了Cache-Control:max-age首部,這個首部使用相對時間來控制保質期,讓一切變得更加合理。舉個例子,我們買了一瓶汽水,如果使用Expires首部來標注保質期,就會這么寫:飲料過期時間:2012年12月21日,如果某個2貨不知道今天多少號,他還真不知道這飲料過期沒,我小時候飲料都這么寫。后來,有個挺有名的賣牛奶的,大概就叫蒙牛,他發明了一種標注保質期的方法,他怎么搞了?他這么寫:保質期:12個月,行,牛逼了,我牛奶一年前就生產出來的牛奶,今天要發給廠家,發之前,先往包裝上印上生產日期(當然是印發貨那天),然后告訴你,明年才過期,這多聰明,搞成相對的,毒死你。也許HTTP 1.1借鑒了這個偉大的發明,於是就有了Cache-Control:max-age首部。
1) Last-Modified&Cache-Control 與 Expire比較
《1》Last-Modified & Cache-Control
設置 header("Last-Modified: ".gmdate("D, d M Y H:i:s", time() )." GMT");
Last-Modified雖然使用了緩存,但是每次打開頁面依然需要向服務器發起http請求,瀏覽器根據用戶的$_SERVER['HTTP_IF_MODIFIED_SINCE']來判斷瀏覽器的內容是否過期,沒過期的話返回304狀態,瀏覽器內容從緩存中讀取。此外 Cache-Control也很重要,如果他的值是max-age=0,max-stable,min-refresh等於0或no-store之類的,緩存是不會被緩存的,每次都會請求服務器。如果是max-age,max-stable,min-refresh[大於0]或only-if-cached,immutable,那么很可能出現 from cache現象。
《2》Expires緩存控制
設置 header("Expires: ".gmdate("D, d M Y H:i:s", time()+$cache_time )." GMT");
狀態碼依然是200,時間依然是舊的時間,Size欄目顯示為from cache,表示內容是直接從瀏覽器讀取,瀏覽器根本就沒有向服務器發起http請求。2)200 OK (from cache) 實現方案
Status 200 Ok (from cache)出現的條件是Cache-Control或者Expires滿足一定的條件。
注意:緩存控制是服務器進行報頭建議,以下報頭是響應頭,不是請求頭
2.1 使用 Cache-Control
1.[(max-age|max-stable|min-refresh) = 緩存創建時間 < 當前系統時間][immutable][only-if-cached] 2.緩存必須帶有ETag或者Last-Modified
Cache-Control:public,Max-Age=84800 ETag:"f6c01531e9c65fa96f3d40409fd030f1"
2.2 Expires不能過期
Expires:Sun, 31 Jul 2016 00:19:47 GMT
以上2種方案只要實現一種即可實現資源from cache
對於瀏覽器而言,還有一種數據是 DataURL協議的數據,這種數據也會從緩存讀取,實現from cache ,但是,如果將所有數據轉碼成DataURL,會出現性能問題。
三.緩存使用技巧
①.無論是開發階段還是生產階段,建議使用Cache-Control + Last-Modified或Tag控制緩存
②.開發階段, 建議使用Cache-Control:[no-cache,no-store|Max-Age=0]這樣可以阻止瀏覽器使用緩存
③無論是開發階段還是生產階段,如果是永遠不會被更改的資源,那么建議使用緩存Cache-Control:[Max-Age=3600][only-if-cached][immutable] 從而實現from cache,減少http請求。
④.如果是生產階段建議使用Cache-Control:Max-Age=3600[no-cache|] ,緩存1小時,每次必須到服務器進行校驗
⑤禁止緩存
Cache-Control: no-cache, no-store, must-revalidate
⑥緩存靜態資源也可以加上public,實現跨域緩存共享
Cache-Control:public, max-age=31536000
⑦ must-revalidate,校驗本地緩存是否過期,過期了才去請求服務器更新緩存
⑧ 默認情況下,Cache-Control:public緩存都回去和服務器校驗的
-
關於 Cache-Control: max-age=秒 和 Expires
Expires = 時間,HTTP 1.0 版本,緩存的載止時間,允許客戶端在這個時間之前不去檢查(發請求)
max-age = 秒,HTTP 1.1版本,資源在本地緩存多少秒。
如果max-age和Expires同時存在,則被Cache-Control的max-age覆蓋。
Expires 的一個缺點就是,返回的到期時間是服務器端的時間,這樣存在一個問題,如果客戶端的時間與服務器的時間相差很大,那么誤差就很大,所以在HTTP 1.1版開始,使用Cache-Control: max-age=秒替代。
Expires =max-age + “每次下載時的當前的request時間”
所以一旦重新下載的頁面后,expires就重新計算一次,但last-modified不會變化