計算機科學中最難的兩件事是緩存失效和命名。
-- Phil Karlton
今天我們來簡要了解一下浏覽器的緩存問題。
浏覽器緩存是指當浏覽器請求一個資源的時候,會在本地保存一份副本,當下一個請求來到的時候,如果是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,還是向源服務器再次發送請求。
一 浏覽器緩存的作用
1. 減少網絡帶寬消耗:無論對于網站運營者或者用戶,帶寬都代表着金錢,過多的帶寬消耗,隻會便宜了網絡運營商。當Web緩存副本被使用時,隻會産生極小的網絡流量,可以有效的降低運營成本。
2. 降低服務器壓力:給網絡資源設定有效期之後,用戶可以重複使用本地的緩存,減少對源服務器的請求,間接降低服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過期機制降低爬取的頻率,也能有效降低服務器的壓力。
三 浏覽器緩存的控制
1. 使用 Meta 标簽控制頁面緩存
前端攻城獅可以在HTML頁面的節點中加入标簽,代碼如下:
<meta http-equiv="Pragma" content="no-cache">
上述代碼的作用是告訴浏覽器當前頁面不被緩存,每次訪問都需要去服務器拉取。使用上很簡單,但隻有部分浏覽器可以支持,而且所有緩存代理服務器都不支持,因為代理不解析HTML内容本身。所以并不推薦使用這種方式控制頁面緩存。
2.使用 HTTP 協議頭控制頁面緩存
在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有以下這些:
Cache-Control 與 Expires
Cache-Control 與 Expires 的作用一緻,都是指明當前資源的有效期,控制浏覽器是否直接從浏覽器緩存取數據還是重新發請求到服務器取數據。隻不過 Cache-Control 的選擇更多,設置更細緻,如果同時設置的話,其優先級高于 Expires。
Last-Modified/ETag 與 Cache-Control/Expires
配置 Last-Modified/ETag 的情況下,浏覽器再次訪問統一 URI 的資源,還是會發送請求到服務器詢問文件是否已經修改,如果沒有,服務器會隻發送一個304回給浏覽器,告訴浏覽器直接從自己本地的緩存取數據;如果修改過那就整個數據重新發給浏覽器。
Cache-Control/Expires 則不同,如果檢測到本地的緩存還是有效的時間範圍内,浏覽器直接使用本地副本,不會發送任何請求。兩者一起使用時,Cache-Control/Expires 的優先級要高于 Last-Modified/ETag。即當本地副本根據 Cache-Control/Expires 發現還在有效期内時,則不會再次發送請求去服務器詢問修改時間(Last-Modified)或實體标識(Etag)了。
一般情況下,使用 Cache-Control/Expires 會配合 Last-Modified/ETag 一起使用,因為即使服務器設置緩存時間, 當用戶點擊“刷新”按鈕時,浏覽器會忽略緩存繼續向服務器發送請求,這時 Last-Modified/ETag 将能夠很好利用304,從而減少響應開銷。
Last-Modified與ETag
你可能會覺得使用 Last-Modified 已經足以讓浏覽器知道本地的緩存副本是否足夠新,為什麼還需要 Etag(實體标識)呢?HTTP1.1 中 Etag 的出現主要是為了解決幾個 Last-Modified 比較難解決的問題:
★ Last-Modified 标注的最後修改隻能精确到秒級,如果某些文件在1秒鐘以内,被修改多次的話,它将不能準确标注文件的新鮮度。
★ 如果某些文件會被定期生成,當有時内容并沒有任何變化,但 Last-Modified 卻改變了,導緻文件沒法使用緩存。
★ 有可能存在服務器沒有準确獲取文件修改時間,或者與代理服務器時間不一緻等情形。
Etag 是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一标識符,能夠更加準确的控制緩存。Last-Modified 與ETag 是可以一起使用的,服務器會優先驗證 ETag,一緻的情況下,才會繼續比對 Last-Modified,最後才決定是否返回304。
四 浏覽器緩存機制在實際開發中的應用
服務器端可以設置緩存規則,但在服務器不能掌控的地方也許會出現一些意外。
1. 緩存會被擠出。
所謂緩存被擠出,因為浏覽器的緩存空間是有限的,所有網站希望緩存的文件都塞在裡面,形成一個先進先出的隊列。所以你即使設置了20年的緩存時間,也基本上是不可能保證有那麼久的生命期。而且用戶也有可能主動清除浏覽器緩存,某些系統清理軟件也可能清理浏覽器緩存。
2. 文件有可能在運營商服務器上被劫持。
第二個問題是用戶的寬帶運營商為了提高速度,可能會在自己某節點服務器上緩存你的文件(比如 style.css?v1),好處是當用戶請求這個文件的時候,運營商無需來你的服務器上請求文件,而自己直接就給出了。 如果你的 querys string 更新了(style.css?v2),按照HTTP規範,這理應被視作一個新的文件。
但是運營商仍然可能會拿自己的緩存,而不是遵循規範。有點可惡對不對?這就是我們在用戶量極大的情況下偵查到的情況,所以,為了保證更新的文件确定能下發到所有的用戶,我們最好是在資源文件改變時,使用前端構建工具修改文件名,而不是僅修改 query string。
以下是業界公認的最佳規則:
對于動态生成的html頁面使用HTTP頭:Cache-Control: no-cache
對于靜态html頁面使用HTTP頭:Last-Modified
其他所有的文件類型都設置Expires頭,并且在文件内容有所修改的時候修改文件名
作者簡介:李凡,英文名Levy,校導Web前端工程師,熱衷鑽研前端技術,對單頁應用開發和前端工程化有着濃厚的興趣。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!