304的請求機制和200有什么不一樣呢?在fiddler中查看304請求的時候突然想到這個問題,就想到研究下這個304請求機制了。
我們自己在nginx上放一個文件,test.png。可以使用下面的地址進行訪問:
http://test.yejianfeng.com/test.png
nginx配置文件如下:
這個的etag關閉是由於nginx默認是開啟etag的,說明見ngx_http_core_module(http://nginx.org/en/docs/http/ngx_http_core_module.html)。
現在我把etag關閉了,這個test.png的HTTP請求如下:
可以看到這里的Response Header 中Last-Modified並沒有設置過期,所以Last-Modified是不生效的。加上沒有其他的相關緩存頭,這個時候,瀏覽器就沒有緩存這個頁面了。所以呢,不管你黏貼URL,F5 還是Ctrl F5,頁面進行的請求Cache-Control都是設置no-cache,所以服務端響應都是200。
下面,修改nginx配置,增加一個expires 1d:
重啟nginx,HTTP請求如下:
可以看出這里的Expires比Date多一天,所以就是服務端告訴客戶端,你給我在本地緩存一天吧。
那么這個時候使用F5:
返回的就是304了,這個時候,就是本地瀏覽器緩存了這個頁面,發送條件請求給服務端,條件請求里面帶一個If-Modified-Since,客戶端詢問服務端,這個文件瀏覽器這邊有緩存,如果你服務端的文件在這個時間點有更改,就發送一個更改后的文件給我,沒有的話就發送一個304就好。
這里還有個問題,這個Last-Modified是怎么定的呢?它就是這個文件在服務器上的最后修改時間。
圖中的15:31和last-Modified的07:31中間的8個小時是時區導致的。
我們touch來修改這個文件的最后修改時間:
然后再F5下這個URL:
服務端返回200了,而且Last-Modified也修改了。這個就很好理解了。
如果我不是使用F5,而是將url直接貼到瀏覽器呢?這個時候,瀏覽器的行為就是如果本地有緩存,就使用本地的緩存,如果本地沒有緩存,就請求服務端。
我們可以做的實驗是這樣:
1 開啟fiddler
2 ctrl + F5,這個時候fiddler中多了一個200響應
3 F5,這個時候fiddler中多了一個304響應
4 打開一個新標簽,在地址欄輸入url:http://test.yejianfeng.com/test.png 這個時候會發現fiddler並沒有任何請求
5 ctrl + F5,這個時候fiddler多一個200響應
所以這里可以驗證之前的文章:HTTP緩存相關頭(http://www.cnblogs.com/yjf512/p/3244882.html)里面說的三種刷新的行為。
回到緩存頭,清空瀏覽器的緩存,把expire的設置去掉,把etag打開
第一次訪問:
看到這里使用ETag了,ETag就相當於一個版本號,HTTP協議中並沒有規定etag的算法,它的具體計算就依靠web服務器自身了。ETag還有普通和弱ETag的區分(http://en.wikipedia.org/wiki/HTTP_ETag)。
第二次訪問的時候:
客戶端發送請求中有個If-None-Match,表示客戶端詢問服務端,如果你這邊的這個文件的tag還是XXXXX,就返回304吧,不是的話就返回200。
所以If-None-Match + ETag是可以控制文件在瀏覽器中的緩存的。
關於緩存的頭,有些是客戶端的:
Cache-Control
If-Modified-Since
If-None-Match
有些是服務端的:
Expire
Last-Modified
ETag
相關這些頭的說明可以看這篇:HTTP緩存相關頭(http://www.cnblogs.com/yjf512/p/3244882.html)
好了,下面說一種情景:
我們再nginx中做了一個rewrite,所有的js都重寫到myjs.php這個腳本,那么問個問題,js在F5的時候會發送條件請求,這個條件請求是不是會觸發php呢?
答案是會的。條件請求也是一個普通的php請求,它會在觸發php的。這個時候如果你需要返回304的話,就需要你在php程序中對If-modified或者If-None-Match進行判斷了。