扼殺 304,Cache-Control: immutable

隨着近些年社交網站的流行,愈來愈多的人學會了「刷」網頁 ── 刷微博,刷朋友圈,刷新聞,刷秒殺頁。這裏的「刷」,就是刷新的意思,在瀏覽器裏,你能夠經過點擊刷新按鈕,或者用快捷鍵,或者移動端的下拉操做來進行刷新。html

但普通網民不知道的是,經過刷新操做致使的頁面加載和經過其餘操做(好比點擊頁面連接,地址欄輸入網址並回車,點擊收藏夾網址等)致使的頁面加載有一點不一樣,那就是刷新操做會給該頁面的請求自己以及頁面裏所引用的資源們(JS,CSS,圖片等)的請求加上 If-Modified-Since 和 If-None-Match 請求頭(若是已經有緩存且有 Last-Modified/ETag 響應頭的話),服務器會根據這兩個請求頭判斷該資源有沒有更新過,若是沒有,就返回不帶響應體的 304 響應,告訴瀏覽器:「用緩存吧」,若是更新過了,則把更新後的資源放在響應體裏返回 200 響應。git

咱們把上面說的這種帶有 If-Modified-Since 或 If-None-Match 請求頭的 HTTP 請求叫作條件請求,除了刷新操做,條件請求還會發生在緩存過時的時候,也就是已緩存時長大於 Cache-Control 響應頭中的 max-age 字段指定的秒數的時候。github

條件請求是設計用來更新資源的,但實際狀況是,在現現在的網站開發中,尤爲是大型網站,會依賴適當的過時時長或者讓用戶手動刷新來更新頁面嗎?好比把緩存時長設置成一小時,新版頁面上線了,用戶都看不到效果,老闆過來問:「這怎麼回事啊,不是上線了嗎」,開發回答:「要等一小時緩存過時啊,你也能夠刷新一下就看到效果了~」。顯然不可能這樣,對於那些有更新需求的靜態資源,常見的是 JS、CSS,咱們都會在它的 URL 里加上點東西,時間戳、版本號、哈希值等,能夠放在 URL 的路徑裏,也能夠放在查詢參數裏,由於只要 URL 變了,瀏覽器就認爲是不一樣的資源,就會從新下載;還有一些靜態資源是徹底沒有更新需求的,好比你在微博上傳的那些圖片,同一個 URL 對應的資源是永遠不會變的。web

上面說的這兩種狀況,實際上是一種,就是它們永遠沒有更新的需求,它們是不可變的,是 immutable 的,304 用在它們身上徹底沒有意義,全是浪費。雖然每一個 304 請求的往返體積只有 1k 左右,但架不住多啊。並且就算只有一個字節,也會致使頁面展示變慢,讀本地文件和讀網絡資源仍是有本質區別的。瀏覽器

Facebook 在一年前意識到了這個問題,它的工程師給制定 HTTP 標準的 IETF 工做組發了封郵件,裏面說到,Facebook 使用版本號來更新靜態資源,還給靜態資源設置了幾乎不可能過時的緩存時長,但發現仍然有 20% 的請求是無心義的條件請求(必然 304),這給服務器性能帶來很大傷害,他們研究發現是由於 Facebook 頁面 pv 有 2% 來自用戶的刷新操做,他們但願 HTTP 協議能給 Cache-Control 響應頭增長一個屬性字段代表該資源永不過時,瀏覽器就不必再爲這些資源發送條件請求了。緩存

今年四月份,Mozilla 的人覺的 Facebook 提的這個建議很好,因而他們在 Firefox 49 裏實現了 Cache-Control: immutable。immutable 的推薦用法是和那些超大的 max-age 配合使用,好比 1年:Cache-Control: max-age=31536000, immutable,甚至 10年, 但一般狀況下,1 年就夠了,由於:1. 對於單個緩存來講,它在某個瀏覽器裏存活的時長不可能超過一年,瀏覽器的緩存空間都有上限,Firefox 256M,Chrome 320M,舊的緩存會時不時被清掉。2. 一個用戶不大可能一年後還來同一個頁面,且那個頁面還沒改版。對緩存時長來講,1 年就表明永遠了。服務器

但這只是推薦作法,immutable 並非真的只能應用在那些永不過時的資源上,也能夠配合較小的 max-age 來使用,好比一些我的博客,或者一些不太講究及時更新的站點,能夠設置成 Cache-Control: max-age=3600, immutable,代表該資源能存活一小時,在一小時以內,即使用戶刷新也不要發送條件請求,在過時以後,瀏覽器會發送不帶一個不帶 If-Modified-Since 和 If-None-Match 的請求來更新資源,這裏須要注意,一旦被標誌成 immutable,則這個資源不可能返回 304 響應了,只有 200。網絡

目前 Firefox 的實現裏,只對 HTTPS 資源開放 immutable 屬性的支持,我經過 Fiddler 在本地篡改了淘寶搜索頁面 https://s.taobao.com/search?q=連衣裙 裏全部資源的 Cache-Control 響應頭,在原值尾部加上 「, immutable」。篡改以前,假如我刷新一下此頁面,會致使數十個 304 響應:app

篡改以後的刷新效果:frontend

注意那些帶有 cached 字樣的 200 請求,那些請求實際上根本不是真正的請求,只是一次本地讀取文件的操做。

目前 Facebook 尚未反饋 immutable 的測試數據,畢竟 Firefox 49 還不是正式版,之後應該會有的。不過考慮到如今 Firefox 的市場佔有率,也許 Chrome 實現以後纔會獲得更多人的關注, Chrome 也表示了有意願去實現。不過我在 GitHub 搜了一下,卻是發現 W3C 的網站Firefox 附加組件網站準備實現。

immutable 只有在你的網站被頻繁刷新的狀況下才有較大的意義。還有雖然它是向後兼容的,但可能一些 CDN 服務器在識別 Cache-Control 時因不認識這個屬性,致使最終返回給瀏覽器的響應丟失了 immutable,推特上有反應 Akamai 就這麼幹了。

少數人知道的強制刷新功能(Ctrl+F5/Shift+Command+R)以及開發者工具的跳過緩存功能優先級應比 immutable 更高。

相關文章
相關標籤/搜索