瀏覽器緩存機制剖析

瀏覽器對于請求資源, 流程如圖所示:

可以看到瀏覽器的緩存機制分為兩個部分:

1链瓦、當前緩存是否過期拆魏?

2、服務(wù)器中的文件是否有改動慈俯?

第一步:判斷當前緩存是否過期

這是判斷是否啟用緩存的第一步渤刃。如果瀏覽器通過某些條件(條件之后再說)判斷出來,ok現(xiàn)在這個緩存沒有過期可以用贴膘,那么連請求都不會發(fā)的卖子,直接是啟用之前瀏覽器緩存下來的那份文件,此時狀態(tài)碼為200

第二步:判斷服務(wù)器中的文件是否有改動

1刑峡、緩存過期洋闽,文件有改動,那么下載新文件突梦,此時狀態(tài)碼為200

2诫舅、緩存過期,文件無改動宫患,那么服務(wù)器只會給你返回一個頭信息(304)刊懈,瀏覽器讀取304后,就會去讀取過期緩存文件娃闲。

如何判斷緩存的過期以及文件的變動虚汛?

瀏覽器擁有一系列成熟的緩存策略. 按照發(fā)生的時間順序分別為存儲策略,?過期策略,?協(xié)商策略,? 其中存儲策略在收到響應(yīng)后應(yīng)用,?過期策略,?協(xié)商策略在發(fā)送請求前應(yīng)用. 流程圖如下所示.

判斷緩存過期,主要還是靠HTTP頭皇帮,廢話不多說, 我們先來看兩張表格

http header中與緩存有關(guān)的key

key描述存儲策略過期策略協(xié)商策略

Cache-Control指定緩存機制,覆蓋其它設(shè)置????

Pragmahttp1.0字段,指定緩存機制??

Expireshttp1.0字段,指定緩存的過期時間??

Last-Modified資源最后一次的修改時間??

ETag唯一標識請求資源的字符串??

2.緩存協(xié)商策略用于重新驗證緩存資源是否有效, 有關(guān)的key如下.

key描述

If-Modified-Since緩存校驗字段, 值為資源最后一次的修改時間, 即上次收到的Last-Modified值

If-Unmodified-Since同上, 處理方式與之相反

If-Match緩存校驗字段, 值為唯一標識請求資源的字符串, 即上次收到的ETag值

If-None-Match同上, 處理方式與之相反

下面我們來看下各個頭域(key)的作用.

Cache-Control

瀏覽器緩存里, Cache-Control是金字塔頂尖的規(guī)則, 它藐視一切其他設(shè)置, 只要其他設(shè)置與其抵觸, 一律覆蓋之.

不僅如此, 它還是一個復(fù)合規(guī)則, 包含多種值, 橫跨?存儲策略,?過期策略?兩種, 同時在請求頭和響應(yīng)頭都可設(shè)置.

語法為:?“Cache-Control : cache-directive”.

?Cache-directive共有如下12種(其中請求中指令7種, 響應(yīng)中指令9種):

Cache-directive描述存儲策略過期策略請求字段響應(yīng)字段

public資源將被客戶端和代理服務(wù)器緩存????

private資源僅被客戶端緩存, 代理服務(wù)器不緩存????

no-store請求和響應(yīng)都不緩存??????

no-cache相當于max-age:0,must-revalidate即資源被緩存, 但是緩存立刻過期, 同時下次訪問時強制驗證資源有效性????????

max-age緩存資源, 但是在指定時間(單位為秒)后緩存過期????????

s-maxage同上, 依賴public設(shè)置, 覆蓋max-age, 且只在代理服務(wù)器上有效.??????

max-stale指定時間內(nèi), 即使緩存過時, 資源依然有效????

min-fresh緩存的資源至少要保持指定時間的新鮮期????

must-revalidation?/?proxy-revalidation如果緩存失效, 強制重新向服務(wù)器(或代理)發(fā)起驗證(因為max-stale等字段可能改變緩存的失效時間)????

only-if-cached僅僅返回已經(jīng)緩存的資源, 不訪問網(wǎng)絡(luò), 若無緩存則返回504??

no-transform強制要求代理服務(wù)器不要對資源進行轉(zhuǎn)換, 禁止代理服務(wù)器對?Content-Encoding,?Content-Range,?Content-Type字段的修改(因此代理的gzip壓縮將不被允許)????

假設(shè)所請求資源于4月5日緩存, 且在4月12日過期.

當max-age 與 max-stale 和 min-fresh 同時使用時, 它們的設(shè)置相互之間獨立生效, 最為保守的緩存策略總是有效. 這意味著, 如果max-age=10 days, max-stale=2 ? ? ? ? ? ?days, min-fresh=3 days, 那么:

根據(jù)max-age的設(shè)置, 覆蓋原緩存周期, ?緩存資源將在4月15日失效(5+10=15);

根據(jù)max-stale的設(shè)置, 緩存過期后兩天依然有效, 此時響應(yīng)將返回110(Response is stale)狀態(tài)碼, 緩存資源將在4月14日失效(12+2=14);

根據(jù)min-fresh的設(shè)置, 至少要留有3天的新鮮期, 緩存資源將在4月9日失效(12-3=9);

由于客戶端總是采用最保守的緩存策略, 因此, 4月9日后, 對于該資源的請求將重新向服務(wù)器發(fā)起驗證.

技術(shù)細節(jié):must-revalidate,no-cache,max-age=0,no-store,? ? ? ? ? ? ?

must-revalidate:? ?如果你配置了max-age信息卷哩,當緩存資源仍然新鮮(小于max-age)時使用緩存,否則需要對資源進行驗證属拾。所以must-revalidate可以和max-age組合使用Cache-Control: must-revalidate, max-age=60

no-cache: 雖然字面意義是“不要緩存”将谊。但它實際上的機制是冷溶,仍然對資源使用緩存,但每一次在使用緩存之前必須(MUST)向服務(wù)器對緩存資源進行驗證瓢娜。

max-age=0:告知瀏覽器挂洛,資源已經(jīng)過期了礼预,你應(yīng)該(SHOULD)對資源進行重新驗證了眠砾;在重新獲取資源之前,先檢驗ETag/Last-Modified托酸。而no-cache則是告訴瀏覽器在每一次使用緩存之前褒颈,你必須(MUST)對資源進行重新驗證。

區(qū)別在于:SHOULD是非強制性的励堡,而MUST是強制性的谷丸。在no-cache的情況下,瀏覽器在向服務(wù)器驗證成功之前絕不會使用過期的緩存資源应结,而max-age=0則不一定了刨疼。

no-store:? 不使用任何緩存。有趣的事情是鹅龄,雖然no-cache意為對緩存進行驗證揩慕,但是因為大家廣泛的錯誤的把它當作no-store來使用,所以有的瀏覽器也就附和了這種設(shè)計扮休。這是一個典型的劣幣驅(qū)逐良幣

不管是max-age=0還是no-cache迎卤,都會返回304(資源無修改的情況下),no-store才是真正的不進行緩存玷坠。

public VS. private

要知道從服務(wù)器到瀏覽器之間并非只有瀏覽器能夠?qū)Y源進行緩存蜗搔,服務(wù)器的返回可能會經(jīng)過一些中間(intermediate)服務(wù)器甚至甚至專業(yè)的中間緩存服務(wù)器,還有CDN八堡。而有些請求返回是用戶級別樟凄、是私人的,所以你可能不希望這些中間服務(wù)器緩存返回兄渺。此時你需要將Cache-Control設(shè)置為private以避免暴露缝龄。

所以綜上,關(guān)于如何設(shè)計緩存機制溶耘,還是要依據(jù)你的需求而定二拐,可以通過下面的這棵決策樹決定:

Expires

Expires:Wed,?05?Apr?2017?00:55:35?GMT1

即到期時間, 以服務(wù)器時間為參考系, 其優(yōu)先級比?Cache-Control:max-age?低, 兩者同時出現(xiàn)在響應(yīng)頭時,?Expires將被后者覆蓋.?如果Expires,?Cache-Control: max-age, 或?Cache-Control:s-maxage?都沒有在響應(yīng)頭中出現(xiàn), 并且也沒有其它緩存的設(shè)置, 那么瀏覽器默認會采用一個啟發(fā)式的算法, 通常會取響應(yīng)頭的Date_value - Last-Modified_value值的10%作為緩存時間.

如下資源便采取了啟發(fā)式緩存算法.

其緩存時間為?(Date_value - Last-Modified_value) * 10%, 計算如下:

const?Date_value?=?new?Date('Thu,?06?Apr?2017?01:30:56?GMT').getTime();const?LastModified_value?=?new?Date('Thu,?01?Dec?2016?06:23:23?GMT').getTime();const?cacheTime?=?(Date_value?-?LastModified_value)?/?10;const?Expires_timestamp?=?Date_value?+?cacheTime;const?Expires_value?=?new?Date(Expires_timestamp);console.log('Expires:',?Expires_value);?//?Expires:?Tue?Apr?18?2017?23:25:41?GMT+0800?(CST)123456

可見該資源將于2017年4月18日23點25分41秒過期, 嘗試以下兩步進行驗證:

1) 試著把本地時間修改為2017年4月18日23點25分40秒, 迅速刷新頁面, 發(fā)現(xiàn)強緩存依然有效(依舊是200 OK (from disk cache)).

2) 然后又修改本地時間為2017年4月18日23點26分40秒(即往后撥1分鐘), 刷新頁面, 發(fā)現(xiàn)緩存已過期, 此時瀏覽器重新向服務(wù)器發(fā)起了驗證, 且命中了304協(xié)商緩存, 如下所示.

3) 將本地時間恢復(fù)正常(即 2017-04-06 09:54:19). 刷新頁面, 發(fā)現(xiàn)Date依然是4月18日, 如下所示.

從?? Provisional headers are shown?和Date字段可以看出來, 瀏覽器并未發(fā)出請求, 緩存依然有效, 只不過此時Status Code顯示為200 OK. ? ? ? ? ? ?(甚至我還專門打開了charles, 也沒有發(fā)現(xiàn)該資源的任何請求, 可見這個200 OK多少有些誤導(dǎo)人的意味)

可見, 啟發(fā)式緩存算法采用的緩存時間可長可短, 因此對于常規(guī)資源, 建議明確設(shè)置緩存時間(如指定max-age 或 expires).

Expires VS. max-age

Expires和max-age都是用于控制緩存的生命周期。不同的是Expires指定的是過期的具體時間凳兵,例如Sun, 21 Mar 2027 08:52:14 ? ? ? ? ? ?GMT百新,而max-age指定的是生命時長秒數(shù)315360000。

區(qū)別在于Expires是 HTTP/1.0 的中的標準庐扫,而max-age是屬于Cache-Control的內(nèi)容饭望,是 HTTP/1.1 中的定義的仗哨。但為了想向前兼容,這兩個屬性仍然要同時存在铅辞。

但有一種更傾向于使用max-age的觀點認為Expires過于復(fù)雜了厌漂。例如上面的例子Sun, 21 Mar 2027 08:52:14 ? ? ? ? ? ?GMT,如果你在表示小時的數(shù)字缺少了一個0斟珊,則很有可能出現(xiàn)出錯苇倡;如果日期沒有轉(zhuǎn)換到用戶的正確時區(qū),則有可能出錯囤踩。這里出錯的意思可能包括但不限于緩存失效旨椒、緩存生命周期出錯等。

判斷文件變動

常用的方式為Etag和Last-Modified堵漱,思路上差不多综慎,這里作者只介紹Last-Modified的用法。

Last-Modified方式需要用到兩個字段:Last-Modified & if-modified-since勤庐。

先來看下這兩個字段的形式:

Last-Modified : Fri , 12 May 2006 18:53:33 GMT

If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT

可以看出其實形式是一樣的示惊,就是一個標準時間。那么怎么用呢愉镰?來看下圖:

當?shù)谝淮握埱竽骋粋€文件的時候米罚,就會傳遞回來一個Last-Modified 字段,其內(nèi)容是這個文件的修改時間岛杀。當這個文件緩存過期阔拳,瀏覽器又向服務(wù)器請求這個文件的時候,會自動帶一個請求頭字段If-Modified-Since类嗤,其值是上一次傳遞過來的Last-Modified的值糊肠,拿這個值去和服務(wù)器中現(xiàn)在這個文件的最后修改時間做對比,如果相等遗锣,那么就不會重新拉取這個文件了货裹,返回304讓瀏覽器讀過期緩存。如果不相等就重新拉取精偿。

Last-Modified

語法:Last-Modified: 星期,日期 月份 年份 時:分:秒 GMT

Last-Modified:?Tue,?04?Apr?2017?10:01:15?GMT1

用于標記請求資源的最后一次修改時間, 格式為GMT(格林尼治標準時間). 如可用new Date().toGMTString()獲取當前GMT時間. Last-Modified ? ? ? ? ? ?是 ETag 的fallback機制, 優(yōu)先級比 ETag 低, 且只能精確到秒, 因此不太適合短時間內(nèi)頻繁改動的資源. 不僅如此, 服務(wù)器端的靜態(tài)資源, 通常需要編譯打包, 可能出現(xiàn)資源內(nèi)容沒有改變, ? ? ? ? ? ?而Last-Modified卻改變的情況弧圆。

If-Modified-Since

語法同上, 如:

If-Modified-Since:?Tue,?04?Apr?2017?10:12:27?GMT1

緩存校驗字段, 其值為上次響應(yīng)頭的Last-Modified值, 若與請求資源當前的Last-Modified值相同, 那么將返回304狀態(tài)碼的響應(yīng), 反之, 將返回200狀態(tài)碼響應(yīng).

ETag

ETag:"fcb82312d92970bdf0d18a4eca08ebc7efede4fe"1

實體標簽, 服務(wù)器資源的唯一標識符, 瀏覽器可以根據(jù)ETag值緩存數(shù)據(jù), 節(jié)省帶寬. 如果資源已經(jīng)改變, etag可以幫助防止同步更新資源的相互覆蓋. ETag 優(yōu)先級比 Last-Modified 高.

If-Match

語法:?If-Match: ETag_value?或者?If-Match: ETag_value, ETag_value, …

緩存校驗字段, 其值為上次收到的一個或多個etag?值. 常用于判斷條件是否滿足, 如下兩種場景:

對于 GET 或 HEAD 請求, 結(jié)合 Range 頭字段, 它可以保證新范圍的請求和前一個來自相同的源, 如果不匹配, 服務(wù)器將返回一個416(Range Not ? ? ? ? ? ? ? ? ? ?Satisfiable)狀態(tài)碼的響應(yīng).

對于 PUT 或者其他不安全的請求,?If-Match?可用于阻止錯誤的更新操作, 如果不匹配, 服務(wù)器將返回一個412(Precondition ? ? ? ? ? ? ? ? ? ?Failed)狀態(tài)碼的響應(yīng).

If-None-Match

語法:?If-None-Match: ETag_value?或者?If-None-Match: ETag_value, ETag_value, …

緩存校驗字段, 結(jié)合ETag字段, 常用于判斷緩存資源是否有效, 優(yōu)先級比If-Modified-Since高.

對于 GET 或 HEAD 請求, 如果其etags列表均不匹配, 服務(wù)器將返回200狀態(tài)碼的響應(yīng), 反之, 將返回304(Not Modified)狀態(tài)碼的響應(yīng). 無論是200還是304響應(yīng), ? ? ? ? ? ? ? ? ? ?都至少返回?Cache-Control,?Content-Location,?Date,ETag,?Expires, and?Vary?中之一的字段.

對于其他更新服務(wù)器資源的請求, 如果其etags列表匹配, 服務(wù)器將執(zhí)行更新, 反之, 將返回412(Precondition Failed)狀態(tài)碼的響應(yīng)。

If-Unmodified-Since

緩存校驗字段, 語法同上. 表示資源未修改則正常執(zhí)行更新, 否則返回412(Precondition Failed)狀態(tài)碼的響應(yīng). 常用于如下兩種場景:

不安全的請求, 比如說使用post請求更新wiki文檔, 文檔未修改時才執(zhí)行更新.

與 If-Range 字段同時使用時, 可以用來保證新的片段請求來自一個未修改的文檔.

ETag&(If-Match&If-None-Match)關(guān)系如同Last-Modified&if-modified-since笔咽。

Etag VS. Last-Modified

Etag和Last-Modified都可以用于對資源進行驗證搔预,而Last-Modified顧名思義,表示資源最后的更新時間叶组。

我們把這兩者都成為驗證器(Validators)拯田,不同的是,Etag屬于強驗證(Strong Validation)甩十,因為它期望的是資源字節(jié)級別的一致船庇;而Last-Modified屬于弱驗證(Weak Validation)吭产,只要資源的主要內(nèi)容一致即可,允許例如頁底的廣告鸭轮,頁腳不同臣淤。

根據(jù)RFC 2616標準中的13.3.4小節(jié),一個使用HTTP 1.1標準的服務(wù)端應(yīng)該(SHOULD)同時發(fā)送Etag和Last-Modified字段窃爷。同時一個支持HTTP 1.1的客戶端邑蒋,比如瀏覽器,如果服務(wù)端有提供Etag的話吞鸭,必須(MUST)首先對Etag進行Conditional Request(If-None-Match頭信息)寺董;如果兩者都有提供覆糟,那么應(yīng)該(SHOULD)同時對兩者進行Conditional Request(If-Modified-Since頭信息)刻剥。如果服務(wù)端對兩者的驗證結(jié)果不一致,例如通過一個條件判斷資源發(fā)生了更改滩字,而另一個判定資源沒有發(fā)生更改造虏,則不允許返回304狀態(tài)。但話說回來麦箍,是否返回還是通過服務(wù)端編寫的實際代碼決定的漓藕。所以仍然有操縱的空間。

強緩存

一旦資源命中強緩存, 瀏覽器便不會向服務(wù)器發(fā)送請求, 而是直接讀取緩存. Chrome下的現(xiàn)象是?200 OK (from disk cache)?或者?200 OK (from ? ? ? ? ? ?memory cache). 如下:

對于常規(guī)請求, 只要存在該資源的緩存, 且Cache-Control:max-age 或者expires沒有過期, 那么就能命中強緩存.

協(xié)商緩存

緩存過期后, 繼續(xù)請求該資源, 對于現(xiàn)代瀏覽器, 擁有如下兩種做法:

根據(jù)上次響應(yīng)中的ETag_value, 自動往request header中添加If-None-Match字段. 服務(wù)器收到請求后, ? ? ? ? ? ? ? ? ? ?拿If-None-Match字段的值與資源的ETag值進行比較, 若相同, 則命中協(xié)商緩存, 返回304響應(yīng).

根據(jù)上次響應(yīng)中的Last-Modified_value, 自動往request header中添加If-Modified-Since字段. 服務(wù)器收到請求后, 拿If-Modified-Since字段的值與資源的Last-Modified值進行比較, ? ? ? ? ? ? ? ? ? ?若相同, 則命中協(xié)商緩存, 返回304響應(yīng).

以上, ETag優(yōu)先級比Last-Modified高, 同時存在時, 前者覆蓋后者. 下面通過實例來理解下強緩存和協(xié)商緩存.

如下忽略首次訪問, 第二次通過?If-Modified-Since?命中了304協(xié)商緩存.

協(xié)商緩存的響應(yīng)結(jié)果, 不僅驗證了資源的有效性, 同時還更新了瀏覽器緩存. 主要更新內(nèi)容如下:

Age:0

Cache-Control:max-age=600

Date:?Wed,?05?Apr?2017?13:09:36?GMTExpires:Wed,?05?Apr?2017?00:55:35?GMT1234

Age:0?表示命中了代理服務(wù)器的緩存, age值為0表示代理服務(wù)器剛剛刷新了一次緩存.

Cache-Control:max-age=600?覆蓋?Expires?字段, 表示從Date_value, 即?Wed, 05 Apr 2017 ? ? ? ? ? ?13:09:36 GMT?起, 10分鐘之后緩存過期. 因此10分鐘之內(nèi)訪問, 將會命中強緩存, 如下所示:

當然, 除了上述與緩存直接相關(guān)的字段外, http header中還包括如下間接相關(guān)的字段.

Pragma

http1.0字段, 通常設(shè)置為Pragma:no-cache, 作用同Cache-Control:no-cache. ? ? ? ? ? ?當一個no-cache請求發(fā)送給一個不遵循HTTP/1.1的服務(wù)器時, 客戶端應(yīng)該包含pragma指令. 為此, 勾選?? 上disable cache時, 瀏覽器自動帶上了pragma字段. 如下:

Age

出現(xiàn)此字段, 表示命中代理服務(wù)器的緩存. 它指的是代理服務(wù)器對于請求資源的已緩存時間, 單位為秒. 如下:

Age:2383321

Date:Wed,?08?Mar?2017?16:12:42?GMT12

以上指的是, 代理服務(wù)器在2017年3月8日16:12:42時向源服務(wù)器發(fā)起了對該資源的請求, 目前已緩存了該資源2383321秒

Date

指的是響應(yīng)生成的時間. 請求經(jīng)過代理服務(wù)器時, 返回的Date未必是最新的, 通常這個時候, 代理服務(wù)器將增加一個Age字段告知該資源已緩存了多久.

Vary

對于服務(wù)器而言, 資源文件可能不止一個版本, 比如說壓縮和未壓縮, 針對不同的客戶端, 通常需要返回不同的資源版本. 比如說老式的瀏覽器可能不支持解壓縮, 這個時候, 就需要返回一個未壓縮的版本; 對于新的瀏覽器, ? ? ? ? ? ?支持壓縮, 返回一個壓縮的版本, 有利于節(jié)省帶寬, 提升體驗. 那么怎么區(qū)分這個版本呢, 這個時候就需要Vary了.

服務(wù)器通過指定Vary: Accept-Encoding, 告知代理服務(wù)器, 對于這個資源, 需要緩存兩個版本: 壓縮和未壓縮. 這樣老式瀏覽器和新的瀏覽器, 通過代理, ? ? ? ? ? ?就分別拿到了未壓縮和壓縮版本的資源, 避免了都拿同一個資源的尷尬.

Vary:Accept-Encoding,User-Agent1

如上設(shè)置, 代理服務(wù)器將針對是否壓縮和瀏覽器類型兩個維度去緩存資源. 如此一來, 同一個url, 就能針對PC和Mobile返回不同的緩存內(nèi)容挟裂。

怎么讓瀏覽器不緩存靜態(tài)資源

實際上, 工作中很多場景都需要避免瀏覽器緩存, 除了瀏覽器隱私模式, 請求時想要禁用緩存, 還可以設(shè)置請求頭:?Cache-Control: no-cache, no-store, must-revalidate?.

當然, 還有一種常用做法: 即給請求的資源增加一個版本號, 如下:

這樣做的好處就是你可以自由控制什么時候加載最新的資源.

不僅如此, HTML也可以禁用緩存, 即在頁面的meta設(shè)置

上述雖能禁用緩存, 但只有部分瀏覽器支持, 而且由于代理不解析HTML文檔, 故代理服務(wù)器也不支持這種方式.

IE8的異常表現(xiàn)

實際上, 上述緩存有關(guān)的規(guī)律, 并非所有瀏覽器都完全遵循. 比如說IE8.

資源緩存是否有效相關(guān).

瀏覽器前提操作表現(xiàn)正常表現(xiàn)

IE8資源緩存有效新開一個窗口加載網(wǎng)頁重新發(fā)送請求(返回200)展示緩存的頁面

IE8資源緩存失效原瀏覽器窗口中單擊 Enter 按鈕展示緩存的頁面重新發(fā)送請求(返回200)

Last-Modified / E-Tag 相關(guān).

瀏覽器前提操作表現(xiàn)正常表現(xiàn)

IE8資源內(nèi)容沒有修改新開一個窗口加載網(wǎng)頁瀏覽器重新發(fā)送請求(返回200)重新發(fā)送請求(返回304)

IE8資源內(nèi)容已修改原瀏覽器窗口中單擊 Enter 按鈕瀏覽器展示緩存的頁面重新發(fā)送請求(返回200)

本文改編自louis的《瀏覽器緩存機制剖析》

文章來源:瀏覽器緩存機制剖析 - Standard Generalized Markup langu - 周陸軍的個人網(wǎng)站

此文如有不妥之處享钞,請告知,謝謝诀蓉!

參考文章

Cache Policy Interaction—Maximum Age and Maximum Staleness

HTTP/1.1: Header ? ? ? ? ? ? ? ? ? ? ? ?Field Definitions

http - What’s the difference between Cache-Control: max-age=0 and no-cache? - ? ? ? ? ? ? ? ? ? ? ? ?Stack Overflow

App 緩存方案:Http 緩存 · baitouwei

Cache-Control ? ? ? ? ? ? ? ? ? ? ? ?- HTTP | MDN

徹底弄懂 Http 緩存機制 基于緩存策略三要素分解法

瀏覽器緩存機制剖析

設(shè)計一個無懈可擊的瀏覽器緩存方案:關(guān)于思路栗竖,細節(jié),ServiceWorker渠啤,以及HTTP/2

no-cache,max-age=0,nostore區(qū)別及304原理

【W(wǎng)eb緩存機制系列】2 – Web瀏覽器的緩存機制

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狐肢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沥曹,更是在濱河造成了極大的恐慌份名,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妓美,死亡現(xiàn)場離奇詭異僵腺,居然都是意外死亡,警方通過查閱死者的電腦和手機壶栋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門辰如,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人委刘,你說我怎么就攤上這事丧没∮ソ罚” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵呕童,是天一觀的道長漆际。 經(jīng)常有香客問我,道長夺饲,這世上最難降的妖魔是什么奸汇? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮往声,結(jié)果婚禮上擂找,老公的妹妹穿的比我還像新娘。我一直安慰自己浩销,他們只是感情好贯涎,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慢洋,像睡著了一般塘雳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上普筹,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天败明,我揣著相機與錄音,去河邊找鬼太防。 笑死妻顶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蜒车。 我是一名探鬼主播讳嘱,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼醇王!你這毒婦竟也來了呢燥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤寓娩,失蹤者是張志新(化名)和其女友劉穎叛氨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棘伴,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡寞埠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了焊夸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仁连。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饭冬,到底是詐尸還是另有隱情使鹅,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布昌抠,位于F島的核電站患朱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏炊苫。R本人自食惡果不足惜裁厅,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侨艾。 院中可真熱鬧执虹,春花似錦、人聲如沸唠梨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姻成。三九已至插龄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間科展,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工糠雨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留才睹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓甘邀,卻偏偏與公主長得像琅攘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子松邪,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容