瀏覽器與HTTP網(wǎng)絡(luò)協(xié)議緩存原理分析
以前項(xiàng)目中遇到了很多瀏覽器緩存相關(guān)的問題,也在網(wǎng)上查過資料,搞過服務(wù)器的配置,來確??蛻舳思虞d服務(wù)器資源的速度和資源有效性。最近仔細(xì)看了下http協(xié)議中和緩存相關(guān)的一些屬性,總結(jié)一下。
瀏覽器緩存原理
文字版描述
①瀏覽器***次訪問服務(wù)器資源 /index.html
在瀏覽器中沒有緩存文件,直接向服務(wù)器發(fā)送請求。
服務(wù)器返回 200 OK,實(shí)體中返回 index.html文件內(nèi)容,并設(shè)置一個緩存過期時間,一個文件修改時間,一個根據(jù)index.html內(nèi)容計(jì)算出來的實(shí)體標(biāo)記Entity Tag,簡稱Etag。
瀏覽器將/index.html路徑的請求緩存到本地。
②瀏覽器第二次訪問服務(wù)器資源 /index.html
由于本地已經(jīng)有了此路徑下的緩存文件,所以這一次就不直接向服務(wù)器發(fā)送請求了。
首先,進(jìn)行緩存過期判斷。瀏覽器根據(jù)①中設(shè)置緩存過期時間判斷緩存文件是否過期。
情景一:若沒有過期,則不向服務(wù)器發(fā)送請求,直接使用緩存中的結(jié)果,此時我們在瀏覽器控制臺中可以看到 200 OK(from cache) ,此時的情況就是完全使用緩存,瀏覽器和服務(wù)器沒有任何交互的。
情景二:若已過期,則向服務(wù)器發(fā)送請求,此時請求中會帶上①中設(shè)置的文件修改時間,和Etag
然后,進(jìn)行資源更新判斷。服務(wù)器根據(jù)瀏覽器傳過來的文件修改時間,判斷自瀏覽器上一次請求之后,文件是不是沒有被修改過;根據(jù)Etag,判斷文件內(nèi)容自上一次請求之后,有沒有發(fā)生變化
情形一:若兩種判斷的結(jié)論都是文件沒有被修改過,則服務(wù)器就不給瀏覽器發(fā)index.html的內(nèi)容了,直接告訴它,文件沒有被修改過,你用你那邊的緩存吧—— 304 Not Modified,此時瀏覽器就會從本地緩存中獲取index.html的內(nèi)容。此時的情況叫協(xié)議緩存,瀏覽器和服務(wù)器之間有一次請求交互。
情形二:若修改時間和文件內(nèi)容判斷有任意一個沒有通過,則服務(wù)器會受理此次請求,之后的操作同①
我的文字表達(dá)能力可能有限,為了盡量把這個流程描述清楚一點(diǎn),下面
一圖以蔽之
緩存相關(guān)首部字段
request緩存相關(guān)首部字段
① cache-control 用來做緩存過期判斷
常用指令:
no-cache 不直接使用緩存,始終向服務(wù)器發(fā)起請求
max-age 緩存過期時間,是一個時間數(shù)值,比如3600秒,設(shè)置為0的時候效果等同于no-cache
s-maxage 給緩存代理用的指令,對直接返回資源的server無效,當(dāng)s-maxage生效時,會忽略max-age的值
only-if-cached 若有緩存,則只使用緩存,若緩存文件出問題了,請求也會出問題
② Pragma 用來做緩存過期判斷
它可以取值no-cache
這是一個http1.0遺留的字段,當(dāng)它和cache-control同時存在的時候,會被cache-control覆蓋
③ if-match / if-none-match 用來做資源更新判斷
這個指令會把緩存中的Etag傳給服務(wù)器,服務(wù)器用它來和服務(wù)器端的資源Etag進(jìn)行對比,若不一致則證明資源被修改了,需要響應(yīng)請求為 200 OK
④ if-modified-since 用來做資源更新判斷
這個指令會把文件的上一次緩存中的文件的更新時間傳給服務(wù)器,服務(wù)器判斷文件在這個時間點(diǎn)后是否被修改,如果被修改過則需要響應(yīng)請求為200 OK
response緩存相關(guān)首部字段
① cache-control 用來設(shè)置緩存過期時間
常用指令:
no-cache 讓客戶端不直接使用緩存,始終向服務(wù)器發(fā)起請求,不設(shè)置默認(rèn)是這個,上邊截圖中的請求就是省略了,所以客戶端不會直接使用緩存。
max-age 緩存過期時間,是一個時間數(shù)值,比如3600秒,設(shè)置為0的時候效果等同于no-cache
s-maxage 給緩存代理用的指令,對直接返回資源的server無效,當(dāng)s-maxage生效時,會忽略max-age的值
private/public 默認(rèn)是private,只在一個瀏覽器中緩存,設(shè)置為public時緩存可被多個用戶共享
② Etag 用來設(shè)置根據(jù)資源內(nèi)容生成的實(shí)體標(biāo)簽
這個值有強(qiáng)tag和弱tag,區(qū)別是計(jì)算方式不同,只有強(qiáng)tag才會在資源被更新的時候立即發(fā)生變化,請求首部中的if-match/if-none-match字段就會傳回這個值給服務(wù)端
③ age
這個字段用來告訴客戶端,這個response是在多久前被創(chuàng)建的,單位為秒,緩存服務(wù)器返回資源的時候必須創(chuàng)建此字段
實(shí)體首部緩存相關(guān)字段
response的head里邊可能還包括實(shí)體首部,實(shí)體首部是緊跟在response首部后邊的。
①last-modified-time ——用來設(shè)置資源***修改時間
②Exprire —— 設(shè)置文件過期時間
這個字段的作用和cache-control相同,不同的是它直接指定一個緩存過期時間點(diǎn),容易受客戶端時間的影響。
這也是一個遺留的字段,和cache-control同時存在的時候會被后者覆蓋
緩存配置的一些注意事項(xiàng)
① 只有g(shù)et請求會被緩存,post請求不會
② Etag 在資源分布在多臺機(jī)器上時,對于同一個資源,不同服務(wù)器生成的Etag可能不相同,此時就會導(dǎo)致304協(xié)議緩存失效,客戶端還是直接從server取資源??梢宰约盒薷姆?wù)器端etag的生成方式,根據(jù)資源內(nèi)容生成同樣的etag。
③ 系統(tǒng)上線,更新資源時,可以在資源uri后邊附上資源修改時間、svn版本號、文件md5 等信息,這樣可以避免用戶下載到緩存的舊的文件
④ 觀察chrome的表現(xiàn)發(fā)現(xiàn),通過鏈接或者地址欄訪問,會先判斷緩存是否過期,再判斷緩資源是否更新;F5刷新,會跳過緩存過期判斷,直接請求服務(wù)器,判斷資源是否更新。