web客戶端緩存機制

      網友投稿 923 2022-05-29

      Readme

      如果你已經熟悉客戶端的緩存機制,可以直接跳過,看最后一節的代碼規范。

      Bug 場景

      比如我們在服務器發布了一個頁面:http://domain.com/cate/page.html

      在這個頁面當中我們引入了一個樣式文件 style.css

      這時候產品經理告訴你,頁面需要把背景換成灰色。于是你迅速把修改后的 style.css 交給了發布,等發布的同事說OK了之后你欣喜雀躍的告訴產品:改完了!

      產品打開瀏覽器,刷新了 page.html 并沒有看到修改后的效果。

      于是你又不得不告訴產品說:Ctrl+F5試試?

      如果這是一個移動端頁面,那就沒有辦法給產品經理的iPhone上裝一個 Ctrl 和 F5 鍵了。

      問題原因

      簡單來講,當你訪問一個頁面的時候,頁面引入的資源(assets)以及頁面自身都會被瀏覽器下載到你自己的電腦上。當你再次訪問同一個頁面,你電腦的瀏覽器會先從你電腦中查找上一次的“訪問痕跡”,如果有這個文件記錄,就不會去服務器請求這個文件。

      頁面中的圖片,音視頻,外引js腳本、css文件都會被緩存。

      當然,服務器端也會有緩存,這時候通過 Ctrl+F5 就無效了(本文不做討論)。

      為什么要緩存

      用戶不需要每次瀏覽都重新去服務器取文件,為服務器減輕了半數以上的壓力。

      從用戶角度,大大縮短了網頁的加載時間。

      緩存規則

      問題來了,如果瀏覽器緩存了文件,服務器文件有了更新,怎么通知瀏覽器更新文件呢?

      我們可以在 http 頭信息(header)里面設定該文件緩存的有效期。

      打開 Chrome 的控制臺,查看網絡請求,我們會看到如下信息。

      其中,Expires 和 Cache-Control 字段控制著這個文件在瀏覽器緩存的失效。Expires 指在這個時間點以前,這個文件緩存都是有效的。Cache-Control 中的 max-age 是說從 Date 字段的時間開始算,43200 秒以內,這個文件緩存是有效的。

      Expires 是 HTTP1.0 就有的,max-age 是 HTTP1.1 提出的,所以低版本瀏覽器不支持 max-age。max-age 比 Expires 更好(因為一個時間長度比寫死一個時間點更有靈活性,也更符合“有效期”的邏輯),優先級更高。

      Expires 詳情

      Cache-Control 詳情

      這兩個值在 html 頁面中都是可以設置的。在 html 的 meta http-equiv 中可以設置文件的頭信息。如:

      我們也可以設置不緩存這個頁面,如:

      后端語言在輸出 html 的時候也可以設置相應的頭信息(header)來控制緩存。下面是一個 JSP 示例:

      <% response.setHeader("expires","sat,6?May?1995?12:00:00?GMT");?//將expire時間設置為一個過去時間或0,-1等response.setHeader("cache-control","no-store,no-cache,must-revalidadate");?//設置HTTP/1.1?cache-control頭response.addHeader("cache-control",?"post-check=0,pre-check=0");?//設置IE?擴展HTTP/1.1?no-cache?headerresponse.setHeader("Pragma",?"no-cache");?//設置標準HTTP/1.0?no-cache?header%>

      但是如果是其他資源文件(css、img、js等),我們可以通過web服務器配置來設置,比如 Nginx 可以通過在 .conf 文件中設置 Expires。下面代碼分別為圖片設置30天緩存、為 js 和 css 設置12小時緩存:

      location?~?.*\.(gif|jpg|jpeg|png|bmp|swf)$?{????expires??????30d; }location?~?.*\.(js|css)?$?{????expires??????12h; }

      那么,是不是緩存過期了,瀏覽器就會去服務器重新請求一份新的文件呢?其實也不是的。當緩存過期,瀏覽器會攜帶頭信息去與服務器的該文件進行比對。如果有更新,就返回狀態碼 200,重新請求文件。如果服務器文件沒有更新,就會返回狀態碼 304,瀏覽器依舊使用緩存中的文件,這樣就不需要再從服務器下載一份 http 的主體信息(body)。

      如果緩存已經過期,瀏覽器在 Request 的時候,攜帶 ETag 和 Last-Modified 與服務器的文件進行比對。

      如果服務器的文件在 Last-Modified(上次修改)之后更新了服務器端的文件,就會重新下載文件主體信息,如果沒有修改,服務器返回狀態碼 304,依舊從緩存讀取文件。

      ETag 是服務器資源的唯一標識符,比對的優先級高于 Last-Modified。

      ETag 詳情

      無論是 Last-Modified 還是 Etag,可以減少傳輸成本,但是不會減少 http 請求數,也就是說,服務器的并發數不會少。

      另外,前面提到的 Cache-control 中 max-age=0 表示緩存立馬過期,請求服務器會返回 304(有緩存的前提)。Cache-Control 值為 no cache 表示總是請求服務器最新文件,不會返回 304。

      狀態碼 200 是請求成功,這里不是說服務器請求成功,也包含了從緩存文件請求成功。

      在 Chrome 瀏覽器,我們還會發現,狀態碼是 200 的文件,也會有 from memory cache(緩存到內存) 和 from disk cache(緩存到本地硬盤) 兩種情況:

      緩存到內存(memory)中的文件,加載的時間幾乎是瞬間。

      至于 Chrome 如何區分 from memory cache 和 from disk cache,目前我也不知道。

      我們遇到不更新的 bug 的時候,多數是頁面外引的css和js,而頁面本身做了修改,只需要刷新一下就可以更新,并不需要 Ctrl+F5 強制刷新。

      這是因為點擊瀏覽器的刷新按鈕(包括微信瀏覽器->右上角->刷新),或者新開窗口,或者地址欄敲回車,都會重新請求 html 頁面(IE8以下可能有出入,但是刷新按鈕肯定會重請求)。

      用戶基本上已經習慣了刷新按鈕,所以 html 極少遇到緩存bug(除非服務器端使用緩存),但是頁面引入的其他資源就很難保證及時刷新了。

      避免緩存

      因為瀏覽器的 http 請求是基于 URL 來的,而且緩存機制不適用于 POST 方法,POST 是不會有緩存的。如果在請求文件的時候添加或修改攜帶的參數,瀏覽器就會認為這是一個新的文件,從而不考慮緩存,直接去請求。比如在地址欄請求新的 html 頁面:

      http://domain.com/sample/page.html?201711011801

      或者在引入文件的時候使用:

      因為 ajax 可以設置頭信息,所以在 ajax 中:

      xmlHttpRequest.setRequestHeader(“If-modified-since”,”0″);

      xmlHttpRequest.setRequestHeader(“Cache-Control”,”no-cache”);

      jquery 使用 ajax 方法的時候設置 cache:false。

      ajax 中也可以使用隨機數參數。

      response.setHeader(“Cache-Control”,”no-cache,must-revalidate”);

      最后,因為瀏覽器的 http 請求是基于 URL 來的,緩存機制不適用于 POST,所以可以用 POST 代替 GET。

      緩存負面影響

      有時候我們打開網站會發現頁面失去了樣式,這種情況多數原因是網絡環境差(加載css失敗)或者頁面錯誤,也有極少可能是緩存在本地的 css 緩存被損壞了,瀏覽器使用了本地緩存,但是并不知道緩存已經失效,而是加載了一個無效的緩存文件。

      當然,這種情況發生的概率小到可以忽略,就算發生了這種情況,我們可以把解決方案推給用戶(用戶只需要清除緩存或者使用 Ctrl+F5 強制刷新即可)。

      個人觀點認為:多數網站都被建議使用緩存,如果說要挑出一個例外,那應該是適用一條法則:

      更新頻率大于用戶訪問頻率

      web客戶端緩存機制

      比如股票實時行情頁面,秒殺頁面……用戶對于頁面數據請求要保持最新,這樣就必須要避免數據緩存。

      代碼規范

      因為我們可以用強制刷新(Ctrl+F5),但是用戶可能不會。開發人員一旦習慣強制刷新之后,就很容易忽略緩存問題。所以強制刷新不是好習慣,因為不是最大限度模擬用戶行為。

      在 html 中引入資源,包括媒體、CSS、JS,如果引入的資源文件是再次發布的,建議添加該文件的版本號(沒有約定版本號可以使用時間串),如:

      在移動端,務必這么做。

      額外的,因為 https 越來越成為主流,為了更好兼容,在使用絕對地址引入外部腳本和樣式文件,切勿限定協議類型。如:

      應該替換為:

      測試環境的臨時解決方案

      在測試的時候,每次修改一下版本號(隨機數)都太麻煩。因為刷新按鈕可以每次都去服務器請求文件,所以我們只要將修改的文件直接放到當前瀏覽器的地址欄,然后刷新一下頁面就可以更新了(注意是和html頁面同一個瀏覽器)。移動端也可以直接打開css或js文件的URI地址刷新一下。

      相關文章:微信內置瀏覽器H5如何清除緩存以及 cookie 和 localStorage 何時清除

      參考資料:

      H5緩存機制淺析

      瀏覽器緩存機制剖析

      淺談瀏覽器http的緩存機制

      緩存 web前端

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:元啟發式算法常用操作詳解
      下一篇:WireShark網絡取證實錄(2)
      相關文章
      亚洲精品视频在线观看免费 | 亚洲成人福利网站| 亚洲熟妇中文字幕五十中出| 国产精品亚洲五月天高清| 国产成人亚洲精品| 日本亚洲精品色婷婷在线影院| 亚洲最新在线视频| 亚洲国产韩国一区二区| 亚洲最大的视频网站| 亚洲午夜国产精品无卡| 亚洲w码欧洲s码免费| 国产v亚洲v天堂a无| 亚洲一区二区三区高清不卡 | 亚洲熟妇无码AV在线播放| 久久亚洲高清综合| 国产亚洲午夜高清国产拍精品| 亚洲美女高清一区二区三区 | 亚洲国产精品成人久久久| 亚洲成a人片在线观看播放| 亚洲a级片在线观看| 欧洲 亚洲 国产图片综合| 亚洲成在人线aⅴ免费毛片| 色欲aⅴ亚洲情无码AV| 亚洲av手机在线观看| 美腿丝袜亚洲综合| 亚洲欧洲精品无码AV| 亚洲av成人无码久久精品| 亚洲高清中文字幕| 亚洲一区二区三区在线| 亚洲性无码一区二区三区| 亚洲AV电影天堂男人的天堂| 婷婷综合缴情亚洲狠狠尤物| 亚洲伊人久久综合中文成人网| 亚洲日韩av无码| 亚洲色图综合网站| 亚洲成年网站在线观看| 在线观看亚洲电影| 亚洲色无码专区在线观看| 亚洲精品高清视频| 亚洲不卡中文字幕| 久久亚洲精品11p|