日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > HTML >内容正文

HTML

前端静态资源缓存最优解以及max-age的陷阱

發(fā)布時(shí)間:2024/1/8 HTML 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端静态资源缓存最优解以及max-age的陷阱 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:點(diǎn)這里

合理的使用緩存可以極大地提高網(wǎng)站資源的利用率,還可以節(jié)約帶寬從而降低服務(wù)器成本。但是很多站點(diǎn)針對(duì)緩存的策略并不合理,甚至是完全無(wú)作為,如果是這樣,就完全沒(méi)有發(fā)揮出緩存的優(yōu)勢(shì),而不合理的策略反而很大程度上會(huì)導(dǎo)致網(wǎng)站在訪問(wèn)時(shí)會(huì)發(fā)生由于靜態(tài)資源的競(jìng)爭(zhēng)關(guān)系而導(dǎo)致依賴的靜態(tài)資源不同步的問(wèn)題(簡(jiǎn)單地說(shuō),就是頁(yè)面發(fā)生了崩壞)。

以下為兩個(gè)最佳靜態(tài)資源緩存實(shí)踐的例子:

資源內(nèi)容長(zhǎng)時(shí)間內(nèi)穩(wěn)定不變

// 設(shè)置緩存時(shí)間為1年 Cache-Control: max-age=31536000

資源的內(nèi)容非常穩(wěn)定,長(zhǎng)時(shí)間內(nèi)都不會(huì)發(fā)生變更,那么我們就可以聲明瀏覽器/CDN可以長(zhǎng)時(shí)間緩存該資源(31536000秒,即一年),只要用戶不手動(dòng)清理瀏覽器緩存,一年內(nèi)源服務(wù)器都不再會(huì)收到(當(dāng)前瀏覽器/CDN)對(duì)該資源的請(qǐng)求。

接下來(lái)看一看實(shí)際的應(yīng)用場(chǎng)景:

第一天

瀏覽器請(qǐng)求了/index-v1.js、/base-v1.css以及/dog-v1.png這三個(gè)資源,時(shí)序圖如下:

第二天

這次瀏覽器請(qǐng)求了/index-v2.js、/base-v2.css以及/dog-v1.png這三個(gè)資源,時(shí)序圖如下:

此處注意:index.js和base.css與第一天請(qǐng)求的版本號(hào)不同。

一年后

在一年的時(shí)間里,瀏覽器再也沒(méi)有請(qǐng)求過(guò)/index-v1.js、/base-v1.css以及/dog-v1.png這三個(gè)資源,瀏覽器緩存就會(huì)把它們給刪掉,時(shí)序圖如下:

所以在這個(gè)例子中,為了讓緩存發(fā)揮最大效率,你要做的并不是更改文件的內(nèi)容,而是應(yīng)該更改資源的URL:

<script src="/index-v3.js"></script> <link rel="stylesheet" href="/base-v3.css"> <img src="/dog-v3.jpg" alt="…">

每一個(gè)靜態(tài)資源URL都應(yīng)該跟隨其內(nèi)容的修改而改變。例如示例index-v1.js中的v1,你對(duì)它的命名不需要有任何限制。它可以是一個(gè)版本號(hào),最后修改的日期,或者根據(jù)內(nèi)容計(jì)算出來(lái)的散列值。

絕大多數(shù)服務(wù)器端的框架都提供了工具來(lái)實(shí)現(xiàn)這一點(diǎn),同樣的在nodejs中有很多優(yōu)秀的庫(kù)來(lái)實(shí)現(xiàn)這個(gè)功能,比如gulp-rev、webpack、fis3。

資源經(jīng)常發(fā)生變更

Cache-Control: no-cache

資源的內(nèi)容經(jīng)常發(fā)生變化,沒(méi)有服務(wù)器的確認(rèn),任何本地緩存的資源都是不可信的,那么我們就可以聲明不讀取該資源的緩存,需要調(diào)用該資源時(shí)每次都嘗試向源服務(wù)器獲取。

第一天

第二天

注意:
no-cache并不意味著不緩存。它的意思是在使用緩存資源之前,它必須經(jīng)過(guò)服務(wù)器的檢查(revalidate也可以實(shí)現(xiàn)這個(gè)功能)。
no-store才是告訴瀏覽器不要緩存它。此外,must-revalidate并不意味著必須重新認(rèn)證,它的前提是資源還在max-age的緩存期內(nèi),否則必須重新認(rèn)證。

在此模式下 ,你也可以將ETag(你選擇的版本ID)或者Last-modified日期添加到響應(yīng)首部中。客戶端下次獲取資源時(shí),他會(huì)分別通過(guò)If-None-Match(與ETage對(duì)應(yīng))和If-Modified-Since(與Last-Mofied對(duì)應(yīng))兩個(gè)請(qǐng)求首部將值發(fā)送給服務(wù)器。如果服務(wù)器發(fā)現(xiàn)兩次值都是對(duì)等的,就是返回一個(gè)HTTP 304。

如果沒(méi)有發(fā)送ETag和Last-Modified,那么服務(wù)器將始終返回完整的資源內(nèi)容。

但是這種方法有個(gè)缺點(diǎn),就是它每次都會(huì)去服務(wù)器做一次驗(yàn)證,涉及到了網(wǎng)絡(luò)提取,所以它不如第一個(gè)例子那樣可以完全繞過(guò)網(wǎng)絡(luò)。

下面來(lái)看一個(gè)頁(yè)面崩壞的例子:

在經(jīng)常修改內(nèi)容的靜態(tài)資源上使用max-age

當(dāng)前頁(yè)面包含文件/article/、/styles.css和/script.js,他們的緩存策略如下:

// 十分鐘內(nèi)不需要重新認(rèn)證,超過(guò)十分鐘就需要重新認(rèn)證 Cache-Control: must-revalidate, max-age=600

當(dāng)頁(yè)面文件發(fā)生變更時(shí),文件路徑會(huì)發(fā)生變化(如文件名會(huì)包含文件算出的哈希),在十分鐘內(nèi),瀏覽器將會(huì)一直使用緩存住的內(nèi)容,而不會(huì)去服務(wù)器請(qǐng)求最新的資源 ;超過(guò)十分鐘,在可用的前提下使用If-Modified-Since和If-None-Match重新進(jìn)行服務(wù)器認(rèn)證。

這個(gè)描述看起來(lái)沒(méi)毛病,那么我們來(lái)看一下實(shí)際使用中會(huì)發(fā)生什么:

第一次請(qǐng)求

幾分鐘后

最終

想象一下,在線上環(huán)境你永遠(yuǎn)不知道瀏覽器前面坐著的是什么樣的人,他很有可能無(wú)意中胡亂地用鼠標(biāo)點(diǎn)點(diǎn)點(diǎn)(比如刪掉了style.css的本地緩存),就打亂了瀏覽器的靜態(tài)資源緩存機(jī)制,導(dǎo)致頁(yè)面發(fā)生了錯(cuò)亂,而且真的很難追蹤(刪除行為無(wú)法記錄)。

在上面的例子中,服務(wù)器實(shí)際上已經(jīng)更新了HTML、CSS和JS,但是頁(yè)面最后使用的是緩存中舊的HTML和JS,以及剛從服務(wù)器下載的最新的CSS,多個(gè)靜態(tài)資源版本之間不匹配的問(wèn)題隨之出現(xiàn),進(jìn)而導(dǎo)致了頁(yè)面的崩壞。

通常,當(dāng)需要對(duì)HTML進(jìn)行重大修改時(shí),我們會(huì)更改CSS文件來(lái)適配新的DOM結(jié)構(gòu),并且更新JS來(lái)配置樣式和DOM的修改。這些資源都是相互依賴的,但攜帶緩存信息的HTTP首部可不管你這些有的沒(méi)的。最終,用戶很有可能會(huì)得到一個(gè)/兩個(gè)靜態(tài)資源新版本,而其他資源都是舊版本。

max-age是相對(duì)于服務(wù)器響應(yīng)時(shí)間的,所以如果所有上述資源都在同一時(shí)間請(qǐng)求,即便它們都被設(shè)置為了相同的max-age時(shí)長(zhǎng),它們?nèi)匀淮嬖诤苄〉母?jìng)爭(zhēng)可能性(畢竟有的資源先返回有的資源后返回)。如果你的某些頁(yè)面不包含JS,或者包含不同的CSS,它們的緩存失效時(shí)間就有可能會(huì)不同步。更惡心的是,瀏覽器始終會(huì)從緩存中刪除和獲取資源,它并不知道這些資源中哪個(gè)是相互依賴的,只要過(guò)了緩存時(shí)間它就會(huì)毫不猶豫地刪掉一個(gè),并不會(huì)刪掉這個(gè)過(guò)期文件所依賴的其他資源。把上面的種種可能性加在一起,就會(huì)大概率出現(xiàn)靜態(tài)資源版本不匹配的問(wèn)題。

不過(guò)還好,我們還有法子來(lái)解決這個(gè)問(wèn)題:

強(qiáng)制刷新瀏覽器或者清除緩存

在強(qiáng)制刷新瀏覽器或者清除緩存后,請(qǐng)求的頁(yè)面以及頁(yè)面內(nèi)的所有資源會(huì)忽略之前的max-age,去服務(wù)器做重新認(rèn)證。因此,如果用戶由于max-age出現(xiàn)問(wèn)題之后,只需要強(qiáng)制刷新或者清緩存就可以修復(fù)問(wèn)題。當(dāng)然,強(qiáng)迫用戶這樣做只會(huì)讓它們降低對(duì)你網(wǎng)站的信任度,認(rèn)為你的網(wǎng)站不靠譜。

原文在這里寫(xiě)了使用serviceWorker來(lái)解決上面的頁(yè)面崩壞問(wèn)題,按筆者的理解,serviceWorker就是對(duì)有依賴關(guān)系的資源進(jìn)行了捆綁,一旦其中一個(gè)過(guò)期,則所有的資源都要重新獲取;但問(wèn)題是serviceWorker并不是所有瀏覽器都支持,即使chrome和firefox也僅在最近的版本才開(kāi)始支持,所以在這里就不貼出來(lái)了,有興趣的同學(xué)可以去原貼看一下。

在內(nèi)容經(jīng)常修改但是URL不變的靜態(tài)資源上使用max-age在通常意義上來(lái)說(shuō)不是一個(gè)好點(diǎn)子,但事實(shí)卻不總是如此。

假如一個(gè)頁(yè)面的max-age為三分鐘,并且在這個(gè)頁(yè)面上不需要考慮靜態(tài)資源的競(jìng)爭(zhēng)關(guān)系,即在這個(gè)頁(yè)面上不存在任何的靜態(tài)資源依賴,那么在這種情況下就可以盡情使用max-age,當(dāng)然,代價(jià)是網(wǎng)站的修改要在三分鐘之后才可以被看到。

不過(guò)要是頁(yè)面存在靜態(tài)資源競(jìng)爭(zhēng)關(guān)系的話,這種法子不好用了,比如我現(xiàn)在有兩個(gè)文章A和B,我現(xiàn)在文章A中添加一個(gè)新的章節(jié),然后在文章B中增加了一個(gè)指向文章A新增章節(jié)的超鏈接。然后我從文章B中訪問(wèn)這個(gè)鏈接,假如文章A的max-age沒(méi)有過(guò)期,那么我訪問(wèn)到的文章A里將會(huì)發(fā)現(xiàn)文章并沒(méi)有那個(gè)新增的章節(jié)。此時(shí)只能等max-age過(guò)期或者強(qiáng)制刷新瀏覽器,再或者清除緩存了。所以,一定要謹(jǐn)慎使用這種方法。

正確使用緩存可以代理巨大的性能收益并且有效節(jié)省服務(wù)器帶寬。既支持版本號(hào)類型的靜態(tài)資源緩存方式也支持服務(wù)器重新認(rèn)證(no-cache、304)的方式。如果你覺(jué)得自己很勇敢,那么大可混合使用max-age,但是前提你得確定自己的HTML中沒(méi)有靜態(tài)資源競(jìng)爭(zhēng)關(guān)系。

最后簡(jiǎn)單匯總一下合理的緩存策略:HTML使用每次服務(wù)端驗(yàn)證的方式來(lái)保證資源是最新的,CSS和JS則可以使用設(shè)置max-age,但發(fā)生變更后更新資源路徑(如重新計(jì)算文件的哈希,并把哈希值加入文件名中)的方式來(lái)保證資源是最新的,當(dāng)然,這樣做需要在HTML中同步更新依賴CSS和JS的資源路徑(雖然之前的CSS和JS仍在緩存期內(nèi),但實(shí)際頁(yè)面已經(jīng)正確使用了更新后的資源)。

總結(jié)

以上是生活随笔為你收集整理的前端静态资源缓存最优解以及max-age的陷阱的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。