影響Cache的幾個(gè)HTTP頭信息

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

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

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

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

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

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

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

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

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

關(guān)于Etag和Last-Modified網(wǎng)上還有更精辟的解釋1、關(guān)于Last-Modified

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

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容