HTTP緩存

HTTP緩存

內容參考自MDN,我進行了一些簡單的歸納和自己的一些理解

緩存的類型

緩存能夠將你瀏覽的網頁數據進行保存,當你下次再次瀏覽該網頁時就能將上次緩存的數據拿來直接用,有什麼好處呢,大家應該都能想得到,可以緩解服務端的壓力,減少獲取資源的時間,用戶體驗也可以直線上升。照這麼說,那我是不是把該網站的所有頁面都緩存下來,那不是很爽?理論上是可以這麼做的,但是網頁不是一成不變的,哪些該緩存,哪些不用緩存就決定了這個網站的體驗。
緩存大致可以分成兩個類型:私有緩存和共享緩存。
在這裏插入圖片描述私有緩存:顧名思義,私有緩存就是瀏覽器本地的緩存,私有緩存可以爲瀏覽器提供向前導航,向後導航、保存網頁、查看源碼等功能。
共享緩存:在瀏覽器和服務器中間加了一個代理服務器,瀏覽器先向這個代理服務器發起請求,經過處理後(權限驗證、緩存匹配等)再轉發給源服務器,他與私有緩存的區別就是他是爲大量的用戶提供服務,一些比較基礎或者熱門的資源就會被重複使用,減少網絡擁堵和延遲。
CDN緩存:CDN(Content delivery networks)緩存,也叫網關緩存、反向代理緩存。CDN緩存一般是由網站管理員自己部署,爲了讓他們的網站更容易擴展並獲得更好的性能。瀏覽器先向CDN網關發起Web請求,網關服務器後面對應着一臺或多臺負載均衡源服務器,會根據它們的負載請求,動態將請求轉發到合適的源服務器上。雖然這種架構負載均衡源服務器之間的緩存沒法共享,但卻擁有更好的處擴展性。從瀏覽器角度來看,整個CDN就是一個源服務器,從這個層面來說,本文討論瀏覽器和服務器之間的緩存機制,在這種架構下同樣適用。

緩存控制頭部信息

禁止進行緩存

禁止存儲任何關於客戶端請求和服務端響應的內容,每次客戶端發起請求都會下載完整的響應內容

Cache-Control: no-store
Cache-Control: no-cache, no-store, must-revalidate

強制確認緩存

當請求頭部如下定義時,服務端會驗證請求中描述的緩存是否過期,如果沒有過期則返回304,然後繼續使用本地的緩存而不進行更新

Cache-Control: no-cache

緩存時間

單位是秒,通過設置該字段類決定緩存的有效時間

Cache-Control: max-age=333333

緩存驗證確認

告訴緩存,我給你準備了一些關於新鮮度的信息,在表現的時候要嚴格遵循之。HTTP允許緩存在某些特定情況下返回過期數據,指定了這個屬性,相對於告訴緩存,你丫必須嚴格遵循我的規則。

Cache-Control: must-revalidate

緩存新鮮度

新鮮度的意思其實就是緩存在瀏覽器中保存的時間,理論上來說,緩存可以被永久的保存在瀏覽器中,但是資源會變啊,我總不能一直使用原來的緩存吧,所以爲了避免這種情況,就得定時的刪掉那些舊的緩存並把它替換成新的緩存才行。所以瀏覽器會服務端會共同制定一個過期時間,當這個時間一過,這個緩存就被看作是過期的,客戶端請求發出的時候,發現這個緩存過期了,它就會在請求中加一個If-None-Match頭,服務器看到這個信息,就知道客戶端是要我看看這個過期的緩存和新的資源相比有沒有變化,服務端發現沒有變化,那就返回一個304,告訴客戶端:你別更新緩存了,和以前的沒變化。可能大家會奇觀,如果服務器更新了東西直接告訴客戶端這個東西更新了不是更方便嗎,的確,但是HTTP是C/S模式,服務端不能向客戶端主動發起請求,所以才需要這麼一個約定。
在這裏插入圖片描述
對於含有特定頭信息的請求,會去計算緩存壽命。比如Cache-control: max-age=N的頭,相應的緩存的壽命就是N。通常情況下,對於不含這個屬性的請求則會去查看是否包含Expires屬性,通過比較Expires(Expires響應頭是一個時間,代表過了這個時間響應過期,0代表時間資源已過期)的值和頭裏面Date屬性的值來判斷是否緩存還有效。如果max-age和expires屬性都沒有,找找頭裏的Last-Modified信息。如果有,緩存的壽命就等於頭裏面Date的值減去Last-Modified的值除以10(注:根據rfc2626其實也就是乘以10%)。

緩存驗證

用戶點擊刷新按鈕時會開始緩存驗證。如果緩存的響應頭信息裏含有"Cache-control: must-revalidate”的定義,在瀏覽的過程中也會觸發緩存驗證。另外,在瀏覽器偏好設置裏設置Advanced->Cache爲強制驗證緩存也能達到相同的效果。

ETags

Etags是一種緩存的強校驗器,相當於緩存的指紋,每個緩存的Etags都不一樣,它的原理是:當瀏覽器向服務器請求某個資源A時,服務器根據資源A計算出一個哈希值並通過Etags響應頭髮送給客戶端,瀏覽器會把Etags值和資源的內容一同緩存到本地,當下次需要對緩存進行驗證時,就會通過If-None-Match: (Etags)的形式發送給服務端,服務端就計算資源A的哈希值與客戶端發送的Etags值進行比較,發生變化了就將新的資源A發送給客戶端(200),沒有變化則返回304。
通過比較Etags值能夠快速確定資源是否發生變化,提高效率,客戶端也不需要把資源發送給服務端,節省了帶寬,etags的唯一性有助於防止資源的同時更新相互覆蓋(“空中碰撞”)。

vary頭的作用

有時候,同一個 URL 可以提供多份不同的文檔,這就要求服務端和客戶端之間有一個選擇最合適版本的機制,這就是內容協商
協商方式有兩種,一種是服務端把文檔可用版本列表發給客戶端讓用戶選,這可以使用 300 Multiple Choices 狀態碼來實現。這種方案有不少問題,首先多一次網絡往返,其次服務端同一文檔的某些版本可能是爲擁有某些技術特徵的客戶端準備的,而普通用戶不一定了解這些細節。舉個例子,服務端通常可以將靜態資源輸出爲壓縮和未壓縮兩個版本,壓縮版顯然是爲支持壓縮的客戶端而準備的,但如果讓普通用戶選,很可能選擇錯誤的版本。所以 HTTP 的內容協商通常使用另外一種方案:服務端根據客戶端發送的請求頭中某些字段自動發送最合適的版本。
可以用於這個機制的請求頭字段又分兩種:內容協商專用字段(Accept 字段)、其他字段
首先來看 Accept 字段,詳見下表:

請求頭字段 說明 響應頭字段
Accept 告知服務器發送何種媒體類型 Content-Type
Accept-Language 告知服務器發送何種語言 Content-Language
Accept-Charset 告知服務器發送何種字符集 Content-Type
Accept-Encoding 告知服務器採用何種壓縮方式 Content-Encoding

當瀏覽器向服務器發送的Accept字段中說明了支持的語言、壓縮等時,服務器就會根據瀏覽器給的說明發送響應的數據格式。
有時候,上面四個 Accept 字段並不夠用,例如要針對特定瀏覽器如 IE6 輸出不一樣的內容,就需要用到請求頭中的 User-Agent 字段。類似的,請求頭中的 Cookie 也可能被服務端用做輸出差異化內容的依據。
由於客戶端和服務端之間可能存在一個或多箇中間實體(如緩存服務器),而緩存服務最基本的要求是給用戶返回正確的文檔。如果服務端根據不同 User-Agent 返回不同內容,而緩存服務器把 IE6 用戶的響應緩存下來,並返回給使用其他瀏覽器的用戶,肯定會出問題 。
所以 HTTP 協議規定,如果服務端提供的內容取決於 User-Agent 這樣「常規 Accept 協商字段之外」的請求頭字段,那麼響應頭中必須包含 Vary 字段,且 Vary 的內容必須包含 User-Agent。
同理,如果服務端同時使用請求頭中 User-Agent 和 Cookie 這兩個字段來生成內容,那麼響應中的 Vary 字段看上去應該是這樣的:

Vary: User-Agent, Cookie

也就是說 Vary 字段用於列出一個響應字段列表,告訴緩存服務器遇到同一個 URL 對應着不同版本文檔的情況時,如何緩存和篩選合適的版本。

參考文章
鏈接:
HTTP 緩存
什麼是Etag
HTTP 協議中 Vary 的一些研究



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章