浏覽器的緩存策略,會暫時將浏覽過的文件緩存在本地磁盤。當用戶重復請求頁面時,告知客戶端頁面並沒有發生改變,可以調用緩存。 那麼如何知道客戶端是否有頁面緩存呢?從 HTTP 協議層面來說,浏覽器發送請求時會先發送如下
HTTP 頭:
Connection Keep-Alive
Date Sun, 06 May 2012 18:00:36 GMT
Last-Modified Sun, 06 May 2012 17:31:02 GMT
Etag ec1f629013925ab0fa4389ba926e8c06
Keep-Alive timeout=15, max=299
Server Apache/2.2.16 (Unix) DAV/2
Vary Accept-Encoding
請注意其中的這兩行,描述了頁面的緩存信息:
Last-Modified Sun, 06 May 2012 17:31:02 GMT
Etag ec1f629013925ab0fa4389ba926e8c06這個情況下,如果服務器響應 304 狀態碼,浏覽器會自覺地從緩存中讀取數據;如果響應 200 狀態碼,不管有沒有客戶端緩存,照樣從服務端讀取。
按照這個理論支撐,比如站長軍團大部分查詢結果都是 ajax 異步獲取的,二次訪問就都可以通過這種方式進行緩存改造。只要客戶端有緩存,就向客戶端發送一個 304 響應狀態碼,然後退出程序執行。
浏覽器發出的請求中包含 If-Modified-Since 和 If-None-Match 兩個參數:
If-Modified-Since 表示詢問數據的最後修改時間是否是某個時間值。然後服務器會檢查數據的最後修改時間,如果是該時間則返回 304 狀態碼,客戶端接收到該狀態碼後直接從本地讀取緩存。這種情況有一個前置條件,即本地必須存在緩存資源,浏覽器才會發送 If-Modified-Since 參數,並且值為上一次服務器返回的 Last-Modified 值。
If-None-Match 類似,它由服務器返回的 Etag 值生成,僅僅用於服務器檢查數據的修改時間,可以是任意值。考慮到 If-Modified-Since 結合 Last-Modified 的方法並不被所有服務器支持,這裡就只考慮使用 etag 的實現。
PHP 中通過 $_SERVER['HTTP_IF_NONE_MATCH'] 可以判斷文件是否被浏覽器緩存,代碼片段如下:
//使用 etag 標記控制緩存
代碼如下 復制代碼 $etag = md5(date('Ymd'));}這裡我使用當日日期來生成 etag,這樣可以保證緩存最多生效一天時間,這個參數可以根據需要修改。
補充說明:
即便是 304 響應,實際上還是會請求服務端,因為需要建立連接來判斷是否需要傳輸數據,304 緩存節約的是靜態資源傳輸的開銷;
另一種緩存是 200 響應時的緩存,不建立連接但請求會響應 200 狀態碼,並從本地直接讀取緩存。