影響Cache的幾個HTTP頭信息

原文鏈接:http://tech110.blog.51cto.com/438717/549764

Http的Cache機制總共有4個組成部分:
Cache-Control、Last-Modified(If-Modified-Since)、Etag(If-None-Match) 、Expires
服務器響應頭:Last-Modified,Etag瀏覽器請求頭:If-Modified-Since,If-None-Match
服務器發出Etag,Last-Modified頭后,下次瀏覽器再進行同樣的請求,則會發出If-None-Match,If-
Modified-Since頭,而后服務器根據這些信息來判斷是否需要發送數據,如果沒有更新,服務器就簡單的
發送一個304狀態告訴瀏覽器用緩存就OK了,不用下載數據了,從而節約了帶寬。
Last-Modified / If-Modified-Since
Last-Modified是響應頭,If-Modified-Since是請求頭。Last-Modified把Web組件的最后修改時間告訴客
戶端,客戶端在下次請求此Web組件的時候,會把上次服務端響應的最后修改時間作為If-Modified-Since
的值發送給服務器,服務器可以通過這個值來判斷是否需要重新發送,如果不需要,就簡單的發送一個
304狀態碼,客戶端將從緩存里直接讀取所需的Web組件。如果有更新,返回HTTP 200和更新的頁面內容,
并且攜帶新的”ETag”和”LastModified”。
使用這個機制,能夠避免重復發送文件給瀏覽器,不過仍然會產生一個HTTP請求。
ETag / If-None-Match
ETag是響應頭,If-None-Match是請求頭。Last-Modified / If-Modified-Since的主要缺點就是它只能精確到秒的級別,一旦在一秒的時間里出現了多次修改,那么Last-Modified / If-Modified-Since是無法體現的。相比較,ETag / If-None-Match沒有使用時間作為判斷標準,而是使用一個特征串。Etag把Web組件的特征串告訴客戶端,客戶端在下次請求此Web組件的時候,會把上次服務端響應的特征串作為If-None-Match的值發送給服務端,服務端可以通過這個值來判斷是否需要從重新發送,如果不需要,就簡單的發送一個304狀態碼,客戶端將從緩存里直接讀取所需的Web組件。因此,HTTP/1.1利用Entity Tag頭提供了更加嚴格的驗證。

當服務器發出響應的時候,可以通過兩種方式來告訴客戶端緩存請求:
第一種是Expires,比如:Expires: Sun, 16 Oct 2016 05:43:02 GMT在此日期之前,客戶端都會認為緩存是有效的。
不過Expires有缺點,比如說,服務端和客戶端的時間設置可能不同,這就會使緩存的失效可能并不能精確的按服務器的預期進行。
第二種是Cache-Control,比如:Cache-Control: max-age=3600
這里聲明的是一個相對的秒數,表示從現在起,3600秒內緩存都是有效的,這樣就避免了服務端和客戶端時間不一致的問題。
但是Cache-Control是HTTP1.1才有的,不適用與HTTP1.0,而Expires既適用于HTTP1.0,也適用于HTTP1.1,所以說在大多數情況下同時發送這兩個頭會是一個更好的選擇,當客戶端兩種頭都能解析的時候,會優先使用Cache-Control基礎知識

  1. 什么是”Last-Modified”?
    在瀏覽器第一次請求某一個URL時,服務器端的返回狀態會是200,內容是你請求的資源,同時有一個Last-Modified的屬性標記(Http Reponse Header)此文件在服務期端最后被修改的時間,格式類似這樣:
    Last-Modified: Fri, 12 May 2006 18:53:33 GMT
    客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送 If-Modified-Since 報頭(Http Request Header),詢問該時間之后文件是否有被修改過:
    If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT
    如果服務器端的資源沒有變化,則自動返回 HTTP 304 (Not Changed.)狀態碼,內容為空,這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啟服務器時,則重新發出資源,返回和第一次請求時類似。從而保證不向客戶端重復發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。 :如果If-Modified-Since的時間比服務器當前時間(當前的請求時間request_time)還晚,Apache會認為是個非法請求

  2. 什么是”Etag”?
    HTTP 協議規格說明定義ETag為“被請求變量的實體值” (參見 —— 章節 14.19)。 另一種說法是,ETag是一個可以與Web資源關聯的記號(token)。典型的Web資源可以一個Web頁,但也可能是JSON或XML文檔。服務器單獨負責判斷記號是什么及其含義,并在HTTP響應頭中將其傳送到客戶端,以下是服務器端返回的格式:
    ETag: "50b1c1d4f775c61:df3"
    客戶端的查詢更新格式是這樣的:
    If-None-Match: "50b1c1d4f775c61:df3"

如果ETag沒改變,則返回狀態304然后不返回,這也和Last-Modified一樣。本人測試Etag主要在斷點下載時比較有用。

Last-Modified和Etags如何幫助提高性能?
聰明的開發者會把Last-Modified 和ETags請求的http報頭一起使用,這樣可利用客戶端(例如瀏覽器)的緩存。因為服務器首先產生 Last-Modified/Etag標記,服務器可在稍后使用它來判斷頁面是否已經被修改。本質上,客戶端通過將該記號傳回服務器要求服務器驗證其(客戶端)緩存。
過程如下:

  1. 客戶端請求一個頁面(A)。
  2. 服務器返回頁面A,并在給A加上一個Last-Modified/ETag。
  3. 客戶端展現該頁面,并將頁面連同Last-Modified/ETag一起緩存。
  4. 客戶再次請求頁面A,并將上次請求時服務器返回的Last-Modified/ETag一起傳遞給服務器。
  5. 服務器檢查該Last-Modified或ETag,并判斷出該頁面自上次客戶端請求之后還未被修改,直接返回響應304和一個空的響應體。

注:
1、Last-Modified和Etag頭都是由Web Server發出的Http Reponse Header,Web Server應該同時支持這兩種頭。
2、Web Server發送完Last-Modified/Etag頭給客戶端后,客戶端會緩存這些頭;
3、客戶端再次發起相同頁面的請求時,將分別發送與Last-Modified/Etag對應的Http Request Header:If-Modified-Since和If-None-Match。我們可以看到這兩個Header的值和Web Server發出的Last-Modified,Etag值完全一樣;
4、通過上述值到服務器端檢查,判斷文件是否繼續緩存;

關于Etag和Last-Modified網上還有更精辟的解釋1、關于Last-Modified

HTTP的Response中還會有另外一個Header叫Last-Modified,比如Last-Modified: Thu, 06 Apr 2006 21:17:12 GMT,瀏覽器訪問一個URI得到這樣的Resposne之后,就知道這個資源最后一次的修改時間,下次需要再次獲得這個資源的時候,會發一個Request給Server,不過這個Request中有一條If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT,如果在Server端在這個日期之后對這個資源進行了修改,就會照常返回這個資源給Client端,但是如果沒有修改,就會返回一個304 (Not Modified) Response而不返回資源,告訴Client端:“這個資源從上次給你之來從來沒改過,你放心用你Cache中的好了。” 一個304 Response比一個靜態資源通常小多了,這樣就節省了網絡帶寬。

2、Last-Modified和Expires的區別
讓我們回過頭來比較一下Expires和Last-Modified這兩個東西,似乎Last-Modified比不上Expires,因為雖然它能夠節省一點帶寬,但是還是逃不掉發一個HTTP請求出去,而Expires卻使得瀏覽器干脆連HTTP請求都不用發,豈不痛快!那還要Last- Modified這個物體干什么?理想狀況的確是這樣,不過當用戶在IE或者Firefox里面按F5或者點擊Refresh按鈕的時候(不是在URL欄里重新輸入一遍URL然后回車),就算對于有Expires的URI,一樣也會發一個HTTP請求出去,所以,Last-Modified還是要用的,而且要和Expires一起用。
3、Etag
除了Last-Modified,HTTP Response中還可能有另外一個Header: ETag,使得Server上的靜態資源有點“版本控制”的味道,假如HTTP Response中包含ETag: "abcdefg1234:0001"等于告訴Client端,你拿到的這個版本的資源有個ID,叫做abcdefg1234:0001,下次需要發Request索要同一個URI的時候,在Request里面加一條If-None-Match: "abcdefg1234:0001"好,Server 端做了一些修改,下次這個Client再來了一個請求,但是這時候資源已經改了,所以返回這個新資源,還有新的tag “ETag: "abcdefg4567:0001"”(這個etag我是胡寫的),這樣,Client端等于Cache了兩份,在需要索要這個資源的時候,可以包含這樣的Header: “If-None-Match: "abcdefg1234:0001" "abcdefg4567:0001"”,這樣,即使Server端頭腦發熱,把這個資源Roll back回原來的版本,依然會返回304 (Not Modified) Response,因為它知道Client端Cache著以前的版本呢,這點功能是Last-Modifed/If-Not-Modified沒法做到的。
4、Etag的弊端
不過ETag/If-None-Match這點功能實在是個雞肋,首先,Server端的資源不大可能Roll Back,更重要的是,有可能造成Client Performance下降。對于只有一個Server的網站,沒什么問題,但是現在稍微上點規模的網站都需要Scale Out,也就是說需要前端一個Load Balancer,后面接多臺Server來處理請求,俗稱Cluster,既然是Cluster,那么每個請求到底返回什么結果應該和分配到哪個 Server無關,不過這個ETag可能就壞事了。假如用戶的第一次請求分配給Server A,返回“ETag: "abcdefg1234:0001"”,但是第二次請求分配給了Server B,Server B上這個資源和Server A上的一模一樣,但是計算出這個資源的ETag是"abcdefg1234:0002",這下麻煩了,雖然內容一樣,但是ETag不匹配,還是浪費了帶寬把資源發送了一遍,冤枉啊!而事實上,不同Server上的ETag很有可能不同,對于Apache,ETag的計算考慮了inode,對于 IIS,ETag考慮了metabase的修改版本,要保證不同server上的這些信息一致,有點小難。不過不是有Last-Modified/If- Not-Modified嗎?Server端看到If-Modified-Since,對照一下時間對得上,不管If-None-Match,可以直接發回304(Not Modified)呀,很不幸,RFC2616對這種情況做了規定,如果既有If-None-Match又有If-Modified-Since,除非兩者不沖突,不然不會返回304。

所以說ETag就是一個害人精,按照Yahoo的建議,別費勁想辦法同步不同Server上的ETag了,干脆就把ETag刪除得了(缺省,Apache和 IIS都是有ETag的),我Sniff了一下Yahoo的若干網頁返回HTTP Response,的確沒有ETag,人家的確是知行合一

對于Apache,在httpd.conf或者.htaccess中加一行就搞定了:
5、Apache中的Etag設置補充:Apache默認開啟Etag,可以使用FileEtag來設置FileETag none|INode|MTime|Size|All從apache的實現中http_etag.c我們可以發現,Apache的Etag包括了Inode|Mtime|Size這些因素。
對于IIS 6,可就有點費勁了,首先,似乎沒有辦法通過Config來把ETag去掉,查了很多資料,問了很多人,似乎能夠去掉ETag的辦法只有寫一個ISAPI Filter來弄,Sniff了一下Microsoft的幾個網頁的結果顯示ETag都穩當當的存在,估計目前真的沒有什么好方法。
只好退而取其次,保證不同Server上的ETag一致了。 IIS對Etag的計算算法是ETag = {Filetimestamp:ChangeNumber}, Filetimestamp保持一致沒什么問題,ChangeNumber是metabase的change number,就有點難保證Cluster中每個Server都一樣了,所以,干脆就把它設成固定值好了,這個連接告訴我們該怎么辦,很可惜,沒有找到徹底刪除ETags的配置。
當然轉載于此方便以后自己查閱!!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容