瀏覽器緩衝機制(1),瀏覽器緩衝機制
瀏覽器緩衝機制之一(經典緩衝)
因為在接手的項目中用到過比較新的HTML5應用緩衝,也用到了經典的緩衝如設定max-age,Etag之類,而之前一直就是在用著沒有去深究其中原理。周末天氣不好,懶得出去了,正好找時間總結下。
1.關於瀏覽器緩衝
記得去年看《HTTP權威指南》的時候,有一章是專門講瀏覽器緩衝的,一年時間過得太快,逝去的時光還真是如同人群中消失的好姑娘,眼看她嫁給別人。我這裡把瀏覽器緩衝分為經典的瀏覽器緩衝(以下簡稱為經典緩衝)和HTML5應用緩衝這兩類。
經典的瀏覽器緩衝其實主要由幾個響應變數來設定,如Cache-Control(設定max-age指定文檔處於新鮮期的秒數),Pragma(Pragma主要用於HTTP1.0,HTTP1.1用Cache-Control),Expires(不推薦,因為它指定的是到期的絕對日期而不是相對秒數),Etag和Last_Modified。其中Etag則對應要求標頭部中的If_None_Match(簡寫為INM),Last_Modified對應If_Modified_Since(簡寫為IMS).新的HTML5應用緩衝則是支援離線儲存文檔,使得文檔資料離線有效,節省了流量,在移動端使用的較多。
2.經典緩衝
預設情況下apache對文檔內容如html,圖片,css等會在響應中加Etag以及Last_Modified。這樣下次請求的時候會帶上INM以及IMS,如果文檔內容沒有修改,那麼返回304 Not Modified,然後就可以從緩衝中取之前緩衝的檔案了;如果文檔從那個時間點後修改過了,那麼返回200和文檔的新內容。下面分別用apache來測試下cache-control,expires,INM以及IMS的效果。
2.1 Cache-Control和Expires
我的apache版本為2.4.10,配置如下,我設定了html檔案的Cache-Control,以及Expires,同時禁用了Last-Modified回應標頭部和Etag。
FileETag none<Files *.html> Header set Cache-Control "max-age=3600"</Files>ExpiresActive OnExpiresByType text/html A20<Files *> Header unset Last-Modified</Files>
我的index.html檔案如下:
<html><head><meta http-equiv="Content-Type" content="text/html; charset=gbk"><title>測試瀏覽器緩衝</title></head><body><p>測試文字</p><img src="/test.gif">測試圖片</img></body></html>
這就設定了html檔案響應加上cache-control回應標頭,如同下面這樣:
Accept-Ranges:bytesCache-Control:max-age=3600Connection:Keep-AliveContent-Length:29Content-Type:text/htmlDate:Mon, 09 Mar 2015 14:17:20 GMTExpires:Mon, 09 Mar 2015 14:18:20 GMTKeep-Alive:timeout=5, max=100Server:Apache/2.4.10 (Ubuntu)
那麼可以看到回應標頭既有Cache-control又有Expires,而且這兩個值我故意設定的不一樣,這個時候以哪個值為準呢?在chrome下面實驗結果表明Cache-control優先順序要高,也就是如果使用期小於新鮮期3600秒,則在地址欄訪問index.html頁面的時候會直接從緩衝中取。
注意這裡chrome有個問題,就是如果在同一個tab下面訪問index.html,不管有沒有到期,都不會從緩衝中取,而當你開啟一個新的tab訪問,則緩衝機制生效,具體原因不明,可能跟chrome內部緩衝策略有關。比如這裡有人提出相同的問題。
2.2 Last-Modified/If-Modified-Since 和 Etag/If-None-Match
這幾個標記可以配合Cache-Control使用。
- Last-Modified:標示響應文檔的最後修改時間。
- If-Modified-Since(IMS):當文檔到期時(比如使用期超過了Cache-Control指定的max-age),如果該響應文檔有Last-Modified的回應標頭部,則會在請求時帶上IMS頭部,值為伺服器文檔的最後修改時間。
- Etag:web伺服器響應請求時,返回Etag頭部用來告知瀏覽器該文檔在伺服器的唯一標示。apache中Etag是對檔案的Inode,大小以及最後修改時間mtime進行hash後得到。
- If-None-Match(INM):當文檔到期時,瀏覽器請求會帶上INM頭部,內容為Etag值。web伺服器會比對Etag值並決定返回304還是200.
對2.1中的配置注釋掉FileTag none和<Files *>
Header unset Last-Modified
</Files>即可開啟Etag和Last-Modified回應標頭部。
如果在要求標頭部中IMS和INM都存在,伺服器會優先驗證INM,只有INM匹配成功後才會繼續比對IMS。
2.3 既有IMS何生INM
根據《http權威指南》上面的描述,之所以存在IMS還要INM主要是有如下幾個原因:
- 有些文檔可能會被周期性重寫,但是實際包含的資料常常是一樣的。儘管內容沒有變化,但是修改日期會發生變化。
- 有些文檔可能被修改了,但是所做修改並不重要,不需要讓世界範圍的換成都重新裝載資料。
- 有些伺服器無法準確判斷頁面最後修改時間。
- 有些伺服器提供的文檔會在毫秒間發生變化,而這個對伺服器以秒為粒度的修改日期就不夠用了。
3.使用者行為與緩衝
使用者行為也會影響瀏覽器緩衝機制。比如你F5會導致Expires/Cache-control無效,用CTRL+F5(某些系統中是Shift+F5)除了Expires/Cache-control外,還會導致Etag/Last-Modified失效。
4.參考資料
- 瀏覽器緩衝機制
- 《HTTP權威指南》
- Is Chrome ignoring Control-Cache: max-age?