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