我司的網(wǎng)站是框架結(jié)構(gòu)的,一個(gè)頁(yè)面里有多個(gè)iframe.正因?yàn)檫@個(gè)原因,每次當(dāng)我自信滿滿的把修改過(guò)的JS文件提交到SVN上后,沒(méi)過(guò)多久,某個(gè)后臺(tái)程序員就會(huì)來(lái)找我說(shuō):怎么JS還報(bào)錯(cuò)呢,我已經(jīng)CTRL+F5了啊,你提交對(duì)了嗎.我只好到他座位上拿起鼠標(biāo)進(jìn)行操作:右鍵->本幀->在新標(biāo)簽中打開(kāi)新幀->CTRL+F5->切換到原標(biāo)簽->F5.這一番操作之后,終于對(duì)了.同樣的事情已經(jīng)發(fā)生過(guò)很多次了.這也證明了不少程序員同志還是不夠了解瀏覽器的緩存機(jī)制.
問(wèn)題的根本原因就是,在火狐里,CTRL+F5清除不了框架頁(yè)面的緩存.包括框架頁(yè)面本身和其所有的嵌入元素(.js,.css,.jpg等).所以本文的真正標(biāo)題是"Firefox中如何才能跳過(guò)緩存刷新框架內(nèi)的頁(yè)面".首先我要講一下相關(guān)的基礎(chǔ)知識(shí).
一.讀取緩存
搞WEB開(kāi)發(fā)的經(jīng)常會(huì)說(shuō):有緩存,CTRL+F5一下.或者:有緩存,CTRL+SHIFT+DEL清一下.那么你知道瀏覽器有幾種方式來(lái)讀取緩存文件嗎.從是否發(fā)送了HTTP請(qǐng)求來(lái)區(qū)分,我覺(jué)的可以分兩種:
1.瀏覽器從服務(wù)器返回的過(guò)期時(shí)間判斷得出,該文件還沒(méi)有過(guò)期,所以直接從緩存文件夾讀取緩存文件,顯示網(wǎng)頁(yè),并沒(méi)有走任何網(wǎng)絡(luò)連接.
2.瀏覽器發(fā)送HTTP請(qǐng)求,請(qǐng)求頭中包含了If-Modified-Since 和 If-None-Match字段.讓服務(wù)器來(lái)判斷是否應(yīng)該讀取緩存文件.如果服務(wù)器返回304響應(yīng),無(wú)響應(yīng)實(shí)體,表示服務(wù)器認(rèn)為這個(gè)文件沒(méi)有變化.可以使用緩存中的對(duì)應(yīng)文件,這時(shí)瀏覽器才會(huì)讀取緩存.(如果不了解HTTP,可以買(mǎi)本<<HTTP權(quán)威指南>>看看.或者直接RFC2616)
我把第一種讀取緩存的方式稱之為"無(wú)請(qǐng)求讀取緩存",第二種方式稱之為"無(wú)修改讀取緩存".
二.刷新方式
這里的刷新方式是指能通過(guò)哪些方式讓一個(gè)網(wǎng)頁(yè)重新加載,我從表現(xiàn)上大概分了三種:
1.最常用的,點(diǎn)擊瀏覽器的刷新按鈕,或者按下F5
2.CTRL+F5,功能是跳過(guò)緩存刷新
3.瀏覽器地址欄上回車(chē),IE里把這種請(qǐng)求方式歸為"導(dǎo)航"操作
在讀取緩存方面,這三種刷新方式的表現(xiàn)都不一樣.第三種方式的表現(xiàn)通常是只刷新主頁(yè)面文件,其他內(nèi)嵌文件全部"無(wú)請(qǐng)求讀取緩存".大部分開(kāi)發(fā)者都不會(huì)這么刷新頁(yè)面,所以本次試驗(yàn)不對(duì)比這種刷新方式.
三.F5和CTRL+F5的區(qū)別
本文的試驗(yàn)部分只針對(duì)F5和CTRL+F5兩種刷新方式做對(duì)比.這里講一下為什么F5不能跳過(guò)緩存,而后者可以.答案就是發(fā)送的請(qǐng)求頭不一樣.而且不同的瀏覽器發(fā)送的請(qǐng)求頭也有一些區(qū)別.
1.F5觸發(fā)的HTTP請(qǐng)求的請(qǐng)求頭中通常包含了If-Modified-Since 或 If-None-Match字段,或者兩者兼有.如果服務(wù)器認(rèn)為被請(qǐng)求的文件沒(méi)有發(fā)生變化,則返回304響應(yīng),也就沒(méi)有跳過(guò)緩存.
2.CTRL+F5觸發(fā)的HTTP請(qǐng)求的請(qǐng)求頭中沒(méi)有上面的那兩個(gè)頭,卻有Pragma: no-cache 或 Cache-Control: no-cache 字段,或者兩者兼有.服務(wù)器看到no-cache這樣的值就會(huì)把最新的文件響應(yīng)過(guò)去.也就跳過(guò)了緩存.
試驗(yàn)題目為:使用F5和CTRL+F5在包含iframe的頁(yè)面上進(jìn)行刷新操作,五大瀏覽器各自的表現(xiàn)不同.本次試驗(yàn)使用Fiddler監(jiān)測(cè)網(wǎng)絡(luò)請(qǐng)求,而且不考慮緩存相關(guān)的HTTP響應(yīng)頭的影響.
主頁(yè)面index.html源碼為
<!DOCTYPE HTML><html> <head> <meta charset="utf-8" /> </head> <body> <iframe src="frame.html"></iframe> <img src="index.jpg" /> <script src="index.js"></script> </body></html>
框架頁(yè)面frame.html源碼為
<!DOCTYPE HTML><html> <head> <meta charset="utf-8" /> </head> <body> <img src="frame.jpg" /> <script src="frame.js"></script> </body></html>
一.IE 9
序號(hào)1-6的請(qǐng)求為F5的操作,序號(hào)7-12的請(qǐng)求為CTRL+F5的操作.可見(jiàn),在IE下,使用CTRL+F5能讓主頁(yè)面和框架頁(yè)面的所有資源文件都跳過(guò)緩存.
二.Firefox 18
序號(hào)1-6的請(qǐng)求為F5的操作,序號(hào)7-9的請(qǐng)求為CTRL+F5的操作.可見(jiàn),在Firefox下,使用CTRL+F5只能讓主頁(yè)面及其資源文件跳過(guò)緩存,而框架頁(yè)面及其資源文件完全"無(wú)請(qǐng)求讀取緩存".
三.chrome 22
序號(hào)1-5的請(qǐng)求為F5的操作,序號(hào)7-9的請(qǐng)求為CTRL+F5的操作.可見(jiàn),在Chrome下,和Firefox類(lèi)似,使用CTRL+F5只能讓主頁(yè)面及其資源文件跳過(guò)緩存,而框架頁(yè)面及其資源文件完全"無(wú)請(qǐng)求讀取緩存".詭異的是,如果在當(dāng)前頁(yè)面按過(guò)一次CTRL+F5,則每次在該頁(yè)面按下F5的時(shí)候,主頁(yè)面的HTTP請(qǐng)求中都會(huì)加入一個(gè)Pragma: no-cache請(qǐng)求頭,也就是說(shuō),瀏覽器會(huì)記憶.序號(hào)1的請(qǐng)求就是這種情況.更詭異的是,F5操作下,frame.html始終是"無(wú)請(qǐng)求讀取緩存",這和其他瀏覽器表現(xiàn)不一樣.更麻煩的是,chrome不能用右鍵把框架頁(yè)面提出來(lái).
四.Opera 12.50
序號(hào)1-6的請(qǐng)求為F5的操作,序號(hào)7-12的請(qǐng)求為CTRL+F5的操作.可見(jiàn),在Opera下,表現(xiàn)更加不一樣.即使只按F5,主頁(yè)面的請(qǐng)求(序號(hào)1)也有Pragma: no-cache請(qǐng)求頭,CTRL+F5下,除了框架頁(yè)面本身(序號(hào)8),所有的資源文件都跳過(guò)了緩存.這一點(diǎn)比較接近IE
五.Safari
序號(hào)1-5的請(qǐng)求為F5的操作,Safari不支持CTRL+F5.和Opera類(lèi)似.F5會(huì)讓主頁(yè)面的請(qǐng)求(序號(hào)1)中包含Pragma: no-cache請(qǐng)求頭.既然不支持跳過(guò)緩存,那么不管是不是框架頁(yè)面,在Safari中只能點(diǎn)菜單清除緩存了.
根據(jù)以上對(duì)比可以看出,只有IE瀏覽器的表現(xiàn)是我們想要的.這里給出Firefox下的解決辦法.
1.安裝擴(kuò)展 http://files.cnblogs.com/ziyunfei/ReloadPassCache.xpi
2.安裝UC腳本 http://files.cnblogs.com/ziyunfei/ReloadPassCache.uc.js
UC腳本是專(zhuān)業(yè)的火狐玩家使用的,這里順便講一下我是如何實(shí)現(xiàn)這個(gè)功能的.有興趣玩火狐腳本的可以看一下.實(shí)在看不懂可以跳過(guò).
//在瀏覽器主窗口綁定keydown事件location == "chrome://browser/content/browser.xul" && addEventListener("keydown", function (event) { //如果按下了CTRL+F5 if (event.which === 116 && event.ctrlKey) { //阻止冒泡和默認(rèn)操作,主要是阻止默認(rèn)的刷新動(dòng)作.否則會(huì)刷兩次 event.preventDefault(); event.stopPropagation(); (function (content) { //為當(dāng)前標(biāo)簽綁上DOMContentLoaded事件,在主頁(yè)面DOM加載完成后,刷新各個(gè)框架 gBrowser.mCurrentBrowser.addEventListener("DOMContentLoaded", function self() { //解綁DOMContentLoaded事件 this.removeEventListener("DOMContentLoaded", self, false); //遍歷刷新所有框架 Array.prototype.slice.call(content.frames).forEach(function (win) { //跳過(guò)緩存刷新 win.location.reload(true); }) }, false); //開(kāi)始刷新主頁(yè)面 content.location.reload(true); })(content) }//捕獲模式,第一時(shí)間觸發(fā)事件處理函數(shù).}, true)
安裝該擴(kuò)展后,按下CTRL+F5能像IE一樣,讓所有的框架頁(yè)面全都跳過(guò)緩存刷新.至于多層框架(框架中的框架),這個(gè)擴(kuò)展不適用,我覺(jué)的各位程序員不會(huì)那么倒霉.
聯(lián)系客服