http緩存深刻研究,200 from cache or 304 not modified?

前幾天看到一篇關於緩存的文章完全弄懂 Http 緩存機制 - 基於緩存策略三要素分解法,以爲頗有意思,因此打算系統學習下Http緩存相關的知識。html

我把緩存分爲緩存存儲緩存對比兩部分。前端

  1. 基本概念node

  2. 命中緩存速度對比算法

  3. 200 from cache  vs  304 Not Modified 瀏覽器

  4. 思考:localStorage存儲緩存

(一)基本概念

(1)緩存存儲

  • Pragma : no-cache  http1.0時期的屬性  爲了兼容會使用服務器

  • Expires:0  http1.0時期的屬性 分佈式

  • Cache-Control  http1.1 中加入的新屬性,它有如下經常使用參數:性能

    • Public/Private 私有緩存/共有緩存學習

    • no-cache:不建議使用本地緩存,但仍然會緩存到本地

    • no-store:不會在客戶端緩存任何數據

    • max-age:比較特殊,是一個混合屬性,替代了Expires的過時時間

舉個栗子:若是要設置客戶端不緩存,併兼容http1.0的方式能夠這樣寫:

Pragma : no-cache 
Expires:0
Cache-Control:no-store

等價於

Pragma : no-cache  // Pragma爲了兼容http1.0
Cache-Control:max-age=0  // 去掉了Expires屬性(下面名詞解釋會說到爲何被去掉),合併到max-age中,

名詞解釋:
私有緩存:《HTTP權威指南》裏面講到了私有緩存的一種就是在瀏覽器裏面輸入  about:cache  能夠查看本身瀏覽器緩存的內容,會給出一個顯示了緩存內容「磁盤緩存統計」頁面,這個能夠看看還挺有意思,能展現很多信息
Expires:過期期限值,GMT格式,是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存取數據,而無需再次請求。不過Expires 是HTTP 1.0的東西,如今默認瀏覽器均默認使用HTTP 1.1,因此它的做用基本忽略。Expires 的一個缺點就是,返回的到期時間是服務器端的時間,這樣存在一個問題,若是客戶端的時間與服務器的時間相差很大(好比時鐘不一樣步,或者跨時區),那麼偏差就很大,因此在HTTP 1.1版開始,使用Cache-Control: max-age=秒替代。

(2)緩存對比

  • Last-Modified  http1.0時期屬性  如今仍在使用

  • ETag(Entity Tag)  http1.1時期新加屬性 ,使用inode+mtime(如下有解釋)來計算。根據實體內容生成的一段hash字符串(相似於MD5或者SHA1以後的結果),能夠標識資源的狀態。 當資源發送改變時,ETag也隨之發生變化。

名詞解釋:
inode :包含文件的元信息,包括如下內容

  • 文件的字節數、文件擁有者的User ID、文件的Group ID

  • 文件的讀、寫、執行權限

  • 文件的時間戳,共有三個:ctime指inode上一次變更的時間,mtime指文>件內容上一次變更的時間,atime指文件上一次打開的時間。

  • 連接數,即有多少文件名指向這個inode、 文件數據block的位置
    mtime:指文件內容上一次變更的時間

2.1爲何用http1.1新推出了ETag

  1. 某些服務器不能精確獲得文件的最後修改時間, 這樣就沒法經過最後修改時間來判斷文件是否更新了。

  2. 某些文件的修改很是頻繁,在秒如下的時間內進行修改. Last-Modified只能精確到秒。

  3. 一些文件的最後修改時間改變了,可是內容並未改變。 咱們不但願客戶端認爲這個文件修改了。

2.2ETag有哪些問題

ETag也有他本身的問題,因此常常在使用中會關閉ETag。舉例來講,同一個文件在不一樣物理機上的inode是不一樣的,這就致使了在分佈式的Web系統中,當訪問落在不一樣的物理機上時會返回不一樣的ETag,進而致使304失效,降級爲200請求。解決辦法也有從ETag算法中剝離inode,只是使用mtime,可是這樣實際上和Last-Modified就同樣了。固然你也能夠額外的作一些改進,使ETag對靜態資源的算法也是經過hash計算的。不過因爲通常咱們會使用CDN技術,所以集羣部署中的ETag問題並不會形成太大的影響,因此折騰的人也不太是不少。  參考:這篇文章hefangshi同窗的回答

(二)命中緩存速度對比

圖片描述
引一張《HTTP權威指南》中的一張圖,能夠看出命中緩存過程:

(1)緩存命中速度

緩存命中 > 緩存再驗證成功 > 緩存未命中 = 緩存再驗證失敗;

1.1緩存命中優先級

Cache-Control http1.1 > Expires > Pragma http1.0來決定是否 (200 from cache)

1.2緩存再驗證成功

根據Last-Modified http1.0 和 ETaghttp1.1 來驗證是否返回 (304 Not Modified) 二者都有,就必須同時驗證,而且二者都知足纔會返回304;

圖片描述

  • 服務端響應頭 Last-Modified 與 客戶端請求頭 If-Modified-Since 對應

  • 服務端響應頭 ETag 與 客戶端請求頭 If-None-Match

(三) 200 from cache vs 304 Not Modified

爲何有時候明明命中了緩存,控制檯中Status顯示的不是 200 from cache ?原來是瀏覽器的緣由:

  • 觸發 200 from cache:

    • 直接點擊連接訪問

    • 輸入網址按回車訪問

    • 二維碼掃描

  • 觸發 304 Not Modified:

    • 刷新頁面時觸發

    • 設置了長緩存、但 Entity Tags 沒有移除時觸發

兩者怎麼選擇

毫無疑問選擇能夠儘可能多的命中緩存,而後靠更新靜態文件的版本號來使緩存失效。關於版本號建議使用 file.xxx.js 的形式而不是 file.js?v=xxx。

能夠看這兩篇文章有講述緣由:

  1. Best Practices for Speeding Up Your Web Site

  2. 大公司裏怎樣開發和部署前端代碼

(四)思考

在研究緩存問題的時候,知乎上看到這個問題:靜態資源(JS/CSS)存儲在localStorage有什麼缺點?爲何沒有被普遍應用? ,看了大神們的答案主要是維護成本實在太高,若是真的速度超快,這點能夠忽略,值得花時間研究,可是若是讀取再執行的速度可能會比瀏覽器直接304性能要低,就徹底沒有必要使用這種方式了。

(五 )參考文章:

  1. 配置錯誤產生的差距:200 OK (FROM CACHE) 與 304 NOT MODIFIED 

  2. http://www.benhallbenhall.com/2012/03/http-codes-200-from-cache-304/

相關文章
相關標籤/搜索