HTTP Cache 為什么讓人很困惑

網(wǎng)上有很多關(guān)于 HTPP Cache 的知識,但個人感覺大部分講的并不好,而這個主題對于 Web 開發(fā)者來說很重要,其實假如想全面了解相關(guān)知識,參考 MDNGoogle 開發(fā)者網(wǎng)站 這兩篇文章就可以了。千萬不要去看 RFC 文檔,個人在看的時候非常費勁,最后放棄了。

本文算一個筆記,闡述其中的關(guān)鍵點,也會說明為什么這個主題不好講(大部分寫的不好的原因在于整體把控做的不好,或者說理解的比較片面)。

要區(qū)分理解 Private browser caches 和 Shared proxy caches

HTTP Cache 包括瀏覽器緩存和代理服務(wù)器緩存(比如 CDN),很多文章在描述的時候沒有有效的區(qū)分這兩者,所以會讓人比較困惑。

瀏覽器緩存的服務(wù)架構(gòu)可能是這樣的:瀏覽器(Cache)=>服務(wù)器。
代理服務(wù)器緩存架構(gòu)可能是這樣的:瀏覽器=>CDN(Cache)=>源服務(wù)器。

不同的 HTTP Cache 解決的問題和使用的場景是不一樣的。個人理解瀏覽器緩存主要是為了避免不必要的請求和大量的網(wǎng)絡(luò)傳輸,而代理服務(wù)器緩存主要是為了讓服務(wù)離用戶更近更有效率(當(dāng)然也解決了請求和網(wǎng)絡(luò)傳輸)。

對于 Web 開發(fā)者來說,可能經(jīng)常遇到的還是瀏覽器緩存,這篇文章主要說的也是此類緩存

而對于 HTTP Cache Header 指令(主要是 Cache-Control)來說,對于這兩種類型的緩存,具體在使用上有不少的區(qū)別,需要仔細分辨。

瀏覽器行為是不可控的

HTTP Cache 是通過 HTTP Cache Header 指令來控制的,指令分為請求和響應(yīng)指令,響應(yīng)指令告訴瀏覽器應(yīng)該做什么(當(dāng)然瀏覽器可以不遵守),而響應(yīng)指令也一定程度上控制未來可能的請求指令。

不過不同瀏覽器針對請求指令處理機制可能是不一樣的,比如瀏覽器“回退動作”、“F5 動作”、“Ctrl +F5” 等動作會發(fā)出不一樣的請求指令。

具體查看下面的圖,通過這張圖,就明白為什么“回退動作”,會從瀏覽器緩存獲取數(shù)據(jù)了。

瀏覽器行為控制指令

使用 HTTP/1.1 標準的指令

HTTP 協(xié)議是一直演變的,不考慮瀏覽器版本和服務(wù)器的問題,盡量使用最新標準協(xié)議的頭,因為假如混著理解,會讓人很困惑,比如 Expires 和 Pargma 等指令都可以被 Cache-Control 指令替代了。

正確理解 Cache-Control 指令

這個指令是一個通用首部字段,就是說這個指令能夠作為請求和響應(yīng)指令,同時這個指令的參數(shù)也有多個,比如說其參數(shù) max-age = 0 在請求和響應(yīng)指令中分別代表什么?在理解的時候一定要分辨清楚。

進一步理解 Cache-Control 指令

理解了這個指令基本上就理解了 HTTP Cache,個人覺得這句話(Cache-Control directives control who can cache the response, under which conditions, and for how long)精確描述了這個指令。

它有三個含義:

(1)能否緩存(針對響應(yīng)來說)

  • private:表示它只應(yīng)該存在與瀏覽器緩存。
  • public:表示它可以緩存在瀏覽器或者 CDN 上。
  • no-cache:這個詞很迷惑,不是代表不能使用緩存,而是代表在使用前必須到服務(wù)器上確認。
  • no-store:表示不允許被緩存。

(2)緩存多久(針對響應(yīng)來說)

  • max-age= 秒,告知瀏覽器這個緩存的有效時間多少。

(3)revalidation(針對響應(yīng)來說,就是條件檢查)

  • must-revalidate:表示瀏覽器必須檢查服務(wù)器,確認本地緩存是否有效,這個參數(shù)和請求參數(shù) max-age = 0 有些類似。

這個指令形象的告訴瀏覽器,你是不是可以緩存這個對象,這個對象緩存時間是多少,是否在每次使用緩存的時候先確認下。

如何使用你的 Cache-Control 策略

對于一個開發(fā)者來說,如何設(shè)定Cache-Control 策略是門藝術(shù),首先要明白資源是什么性質(zhì)的,在此基礎(chǔ)上定義 HTTP Cache 策略,Google 開發(fā)者網(wǎng)站的這張圖形象的描述了策略。

Cache-Control 策略
  • 這個資源是否允許緩存?
  • 客戶端每次使用緩存的時候需要去服務(wù)器校驗嗎?
  • 這個緩存是 Public 的還是 Private?
  • 緩存時間多少?
  • 資源標識符是什么(Etag)?

瀏覽器如何校驗緩存

通過上面的描述,開發(fā)者明白了如何設(shè)置 HTTP Cache ,那么瀏覽器如何選擇是否使用緩存呢?理解了這個會鞏固理解 Cache-Control 策略。

這里面會增加兩個指令,ETag 指令和 Last-modified,分別代表什么含義呢?ETag 表示資源的唯一性,假如這個值變化了代表資源更新了;Last-modified 表示資源最后的更新時間;

通過上面的圖也可以發(fā)現(xiàn),開發(fā)者可以在響應(yīng)的時候輸出這兩個頭信息。那這個指令代表什么意思呢?

當(dāng)瀏覽器發(fā)現(xiàn)本地有緩存,且服務(wù)器指示沒有必要每次使用前去確認,那么瀏覽器可以直接使用本地緩存。

當(dāng)瀏覽器發(fā)現(xiàn)緩存已經(jīng)過期了,那么這個時候可以選擇重新去獲取資源,但是有這么一種情況,服務(wù)器資源其實沒有變化,那么為了減少帶寬使用,服務(wù)器輸出一個 304 HTTP 協(xié)議頭,告訴瀏覽器,你繼續(xù)使用你存儲的緩存把。
問題來了,服務(wù)器怎么知道這個資源沒有變化呢(從瀏覽器緩存生效的那時算),假如在第一次響應(yīng)的時候輸出了 Last-modified 頭(表示資源的最后更新時間),那么客戶端發(fā)現(xiàn)緩存失效的時候,在請求的時候會帶上 if-Modified-Since(其實就是 Last-modified 的值)信息,服務(wù)器一看服務(wù)器上的資源最后更新時間小于或等于 if-Modified-Since 時間,就表示這個資源其實是新的,然后就發(fā)送一個 304 頭。

如何通過 Nginx 來配置

大部分情況下,Nginx 會進行如下配置,但是需要明白含義,

location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
   expires 10d;
}

expires 這個指定會輸出如下的頭:

Cache-Control:max-age=864000
Date:Tue, 28 Mar 2017 10:00:38 GMT
ETag:"5864a0ab-1e75"
Expires:Fri, 07 Apr 2017 10:00:38 GMT
Last-Modified:Thu, 29 Dec 2016 05:35:39 GMT

假如緩存沒有過期就會一直使用,每次也不會去服務(wù)器校驗,假如想每次請求資源的時候都確認下,可以使用以下指令:

location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    expires 10d;
    add_header Cache-Control "no-cache,must-revalidate,max-age=0";
}

動態(tài)程序如何控制

動態(tài)程序要負責(zé)所有的 HTTP Cache 頭輸出,還要自己計算 Etag,直接上代碼看把:

<?php
$now = gmdate("D, d M Y H:i:s", time() ) . " GMT";
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;

if ($if_modified_since && $if_modified_since  >$now){
    header('HTTP/1.1 304 Not Modified');
    exit();
} else {

    $seconds_to_cache = 3600*24;
    $ts = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT";

    header("Last-Modified: $ts");
    header("Cache-Control: no-cache, must-revalidate");
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇文章篇幅比較長,先來個思維導(dǎo)圖預(yù)覽一下。 一、概述 1.計算機網(wǎng)絡(luò)體系結(jié)構(gòu)分層 2.TCP/IP 通信傳輸流 ...
    滌生_Woo閱讀 56,202評論 24 557
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,553評論 19 139
  • 一、概念(載錄于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434閱讀 8,741評論 6 152
  • 本文內(nèi)容大多參考《圖解HTTP》一書 一. 認識代理服務(wù)器 所以講緩存為什么要先扯代理服務(wù)器?別急,讓我們看一下一...
    流光號船長閱讀 2,100評論 0 10
  • 網(wǎng)絡(luò)特有的延遲以及數(shù)據(jù)傳輸?shù)某杀?,制約互聯(lián)網(wǎng)快速獲取Web資源。為此,HTTP協(xié)議引入緩存以空間換時間,使瀏覽器緩...
    大頭8086閱讀 3,195評論 2 12

友情鏈接更多精彩內(nèi)容