前言
上一篇互聯網架構重要組員CDN,很多高級開發都沒有實操過,來看這里老顧介紹了CDN相關的知識,最后留了一下問題,就是緩存控制,今天老顧介紹一下如何控制緩存?
Cache Control響應頭
首先我們先來看一下Cache Control這個概念,我們先看一下訪問一個網站,觀察一下響應頭部

我們發現cache-control的值為max-age=31536000,從字面上面就能夠猜出它的含義,就是服務端告訴客戶端此信息可不可以緩存,以什么樣的策略進行緩存;cache-control有哪些類型的值呢?
1、private:客戶端可以緩存
2、public:客戶端和代理服務器可以緩存
小伙伴們會疑惑什么是代理服務器可以緩存?我們用戶電腦訪問web站點之間,很有可能會經過類似Nginx的反向代理服務器,也有可能會經過我們正向代理的服務器,也有可能會經過CDN網絡;
因此我們中間層的服務節點,發現cache-control的值為private時,就認可只有發起請求的客戶端能夠緩存,作為代理服務節點是不能夠緩存的。如為public時,代理服務器也可以緩存。
3、max-age:緩存的內容將在xxx秒后失效
這個意思就是在客戶端收到信息后,信息會緩存xxx秒;過了xxx秒客戶端必須重新獲取信息。
4、no-store:不緩存請求的任何返回內容
不緩存請求返回的任何內容
5、no-cache:強制向服務器端再驗證一次
no-cache和no-store的區別就是,no-cache會緩存請求返回的內容,而no-store不緩存;但no-cache時,在下次用緩存的內容時,需要向服務器驗證一下,緩存到底能不能用。
邏輯流程圖

流程圖中,服務根據自身的業務,設置cache-control的值為:no-store、no-cache等,如:
Cache-Control: public, max-age=86400
在邏輯流程圖中,有一個環節就是重新驗證,就是驗證緩存內容是否有效,那驗證邏輯是什么,怎么驗證?
ETag驗證
ETag:資源唯一標識
一般會把請求的內容做md5加密,返回唯一的標識;會把ETag的值一起返回給瀏覽器;瀏覽器會把ETag存儲下來。
Etag: "5d8c72a5edda83343d6aere"
下一次請求時將Etag一并帶過去給服務器,服務器只需要比較客戶端傳來的ETag跟自己服務器上該資源的ETag是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。
如果服務器發現ETag匹配不上,那么直接以常規GET 200狀態碼形式將新的資源(當然也包括了新的ETag)發給客戶端;如果ETag是一致的,則直接返回304狀態碼客戶端直接使用本地緩存即可。
那么客戶端是如何把標記在資源上的ETag傳回給服務器的呢?請求報文中有兩個首部字段可以帶上ETag值:
1、If-None-Match: ETag-value
If-None-Match: "5d8c72a5edda83343d6aere" 告訴服務端如果ETag沒匹配上需要重發資源數據,否則直接回送304和響應報頭即可。
當前各瀏覽器均是使用的該請求首部來向服務器傳遞保存的ETag值。
2、If-Match: ETag-value
告訴服務器如果沒有匹配到ETag,或者收到了“*”值而當前并沒有該資源實體,則應當返回412(Precondition Failed) 狀態碼給客戶端。否則服務器直接忽略該字段。
需要注意的是,如果資源是走分布式服務器(比如CDN)存儲的情況,需要這些服務器上計算ETag唯一值的算法保持一致,才不會導致明明同一個文件,在服務器A和服務器B上生成的ETag卻不一樣。
ETag優點:
1、可以更加精確的判斷資源是否被修改,可以識別一秒內多次修改的情況。
2、不存在版本問題,每次請求都回去服務器進行校驗。
缺點:
1、計算ETag值需要性能損耗。
2、分布式服務器存儲的情況下,計算ETag的算法如果不一樣,會導致瀏覽器從一臺服務器上獲得頁面內容后到另外一臺服務器上進行驗證時發現ETag不匹配的情況。
Last-Modified驗證
服務器將資源傳遞給客戶端時,會將資源最后更改的時間以“Last-Modified: GMT”的形式加在實體首部上一起返回給客戶端。
Last-Modified: Sun, 28 Apr 2019 02:23:05 GMT
客戶端會為資源標記上該信息,下次再次請求時,會把該信息附帶在請求頭中一并帶給服務器去做檢查,若傳遞的時間值與服務器上該資源最終修改時間是一致的,則說明該資源沒有被修改過,直接返回304狀態碼,內容為空。
如果兩個時間不一致,則服務器會發回該資源并返回200狀態碼,和第一次請求時類似。這樣保證不向客戶端重復發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。

也類似ETag,客戶端請求報文頭,兩種參數
1、If-Modified-Since: Last-Modified-value
If-Modified-Since: Sun, 28 Apr 2019 02:23:05 GMT
該請求首部告訴服務器如果客戶端傳來的最后修改時間與服務器上的一致,則直接回送304 和響應報頭即可。
當前各瀏覽器均是使用的該請求參數來向服務器傳遞保存的 Last-Modified 值。
2、If-Unmodified-Since: Last-Modified-value
該值告訴服務器,若Last-Modified沒有匹配上(資源在服務端的最后更新時間改變了),則應當返回412(Precondition Failed) 狀態碼給客戶端。
Last-Modified 存在一個問題,如果在服務器上,一個資源被修改了,但其實際內容根本沒發生改變,但修改時間變化了,會導致Last-Modified時間匹配不上而返回了整個實體給客戶端(跟客戶端緩存里有個一模一樣的資源);就是錯誤的判斷內容改變了。
請求流程圖

上面的圖就是總結了一下之前所講的,比較容易理解,不理解回頭重新看。
瀏覽器刷新方式
1、在URI輸入欄中輸入然后回車
看cache-control對應的max-age是否有效,根據上面的流程圖,進入協商機制
2、F5/點擊工具欄中的刷新按鈕/右鍵菜單重新加載
去掉max-age或設置max-age=0,進入上面的流程圖,進入協商機制
3、Ctl+F5/commond+shift+R
去掉cache-control和協商頭,不管有沒有緩存,強制刷新,都要到Server服務器上面獲取數據,返回200狀態碼
協商機制再次說明:比較ETag和Last-Modified到服務端,若服務端一致,沒有變化,則返回狀態碼304,不返回數據;否則返回狀態碼200,返回數據。
動態數據
根據上面的知識,我們去取動態數據時(如:ajax動態請求),服務端就可以利用上面的規則控制客戶端不要緩存,設置cache-control為max-age=0;且不設置ETag和Last-Modified就可以達到不緩存;反之如果要緩存數據,設置相關的值就行了。
CDN自定義緩存策略
1、可自定義目錄的過期時間
不管源服務器的緩存過期是什么規則,CDN服務自定義目錄過期時間,假如1個小時,那1個小時后,CDN設置的緩存目錄里面的內容會過期,會再去源服務器那邊獲取新的信息(簡稱回源)。
2、可自定義后綴名過期時間
可根據后綴名設置緩存策略,如:html、js、css等
3、可自定義對應權重
如設置了后綴名的權重比目錄過期高,那么就遵循后綴名過期規則
4、可通過界面或API強制CDN對應的目錄進行刷新(不一定會成功)
總結
現在的CDN產品已經比較成熟,有后臺控制臺管理進行緩存的配置,如果需要程序控制相關的緩存過期規則,可以用上面介紹的知識點配合使用。今天老顧就介紹到這里,謝謝!!!