天天看點

大話PHP緩存頭

304的請求機制和200有什麼不一樣呢?在fiddler中檢視304請求的時候突然想到這個問題,就想到研究下這個304請求機制了。

我們自己在nginx上放一個檔案,test.png。可以使用下面的位址進行通路:

<a href="http://test.yejianfeng.com/test.png">http://test.yejianfeng.com/test.png</a>

nginx配置檔案如下:

大話PHP緩存頭

這個的etag關閉是由于nginx預設是開啟etag的,說明見ngx_http_core_module(http://nginx.org/en/docs/http/ngx_http_core_module.html)。

現在我把etag關閉了,這個test.png的http請求如下:

大話PHP緩存頭

可以看到這裡的response header 中last-modified并沒有設定過期,是以last-modified是不生效的。加上沒有其他的相關緩存頭,這個時候,浏覽器就沒有緩存這個頁面了。是以呢,不管你黏貼url,f5 還是ctrl f5,頁面進行的請求cache-control都是設定no-cache,是以服務端響應都是200。

下面,修改nginx配置,增加一個expires 1d:

大話PHP緩存頭

重新開機nginx,http請求如下:

大話PHP緩存頭

可以看出這裡的expires比date多一天,是以就是服務端告訴用戶端,你給我在本地緩存一天吧。

那麼這個時候使用f5:

大話PHP緩存頭

傳回的就是304了,這個時候,就是本地浏覽器緩存了這個頁面,發送條件請求給服務端,條件請求裡面帶一個if-modified-since,用戶端詢問服務端,這個檔案浏覽器這邊有緩存,如果你服務端的檔案在這個時間點有更改,就發送一個更改後的檔案給我,沒有的話就發送一個304就好。

這裡還有個問題,這個last-modified是怎麼定的呢?它就是這個檔案在伺服器上的最後修改時間。

大話PHP緩存頭

圖中的15:31和last-modified的07:31中間的8個小時是時區導緻的。

我們touch來修改這個檔案的最後修改時間:

大話PHP緩存頭

然後再f5下這個url:

大話PHP緩存頭

服務端傳回200了,而且last-modified也修改了。這個就很好了解了。

如果我不是使用f5,而是将url直接貼到浏覽器呢?這個時候,浏覽器的行為就是如果本地有緩存,就使用本地的緩存,如果本地沒有緩存,就請求服務端。

我們可以做的實驗是這樣:

1 開啟fiddler

2 ctrl + f5,這個時候fiddler中多了一個200響應

3 f5,這個時候fiddler中多了一個304響應

5 ctrl + f5,這個時候fiddler多一個200響應

大話PHP緩存頭

回到緩存頭,清空浏覽器的緩存,把expire的設定去掉,把etag打開

大話PHP緩存頭

第一次通路:

大話PHP緩存頭

看到這裡使用etag了,etag就相當于一個版本号,http協定中并沒有規定etag的算法,它的具體計算就依靠web伺服器自身了。etag還有普通和弱etag的區分(http://en.wikipedia.org/wiki/http_etag)。

第二次通路的時候:

大話PHP緩存頭

用戶端發送請求中有個if-none-match,表示用戶端詢問服務端,如果你這邊的這個檔案的tag還是xxxxx,就傳回304吧,不是的話就傳回200。

是以if-none-match + etag是可以控制檔案在浏覽器中的緩存的。

關于緩存的頭,有些是用戶端的:

cache-control

if-modified-since

if-none-match

有些是服務端的:

expire

last-modified

etag

我們再nginx中做了一個rewrite,所有的js都重寫到myjs.php這個腳本,那麼問個問題,js在f5的時候會發送條件請求,這個條件請求是不是會觸發php呢?

答案是會的。條件請求也是一個普通的php請求,它會在觸發php的。這個時候如果你需要傳回304的話,就需要你在php程式中對if-modified或者if-none-match進行判斷了。