問(wèn)題描述
vue 項(xiàng)目打包上線之后枕屉,每一次都會(huì)有瀏覽器緩存問(wèn)題啤咽,需要手動(dòng)的清除緩存。這樣用戶(hù)體驗(yàn)非常不好穿稳,所以我們?cè)诖虬渴鸬臅r(shí)候需要盡量避免瀏覽器的緩存。
需要解決的問(wèn)題
1晌坤、程序每次升級(jí)后逢艘,用戶(hù)都不會(huì)因?yàn)榫彺鎲?wèn)題而執(zhí)行的仍然是老的程序。
2泡仗、若程序沒(méi)升級(jí)埋虹,用戶(hù)對(duì)靜態(tài)資源的請(qǐng)求則能用到緩存。
關(guān)于瀏覽器緩存策略娩怎,可以分為這三種:
-
(1)不使用緩存
no-store
永遠(yuǎn)都不在客戶(hù)端存儲(chǔ)資源搔课,永遠(yuǎn)都去原始服務(wù)器去獲取資源。
-
(2)強(qiáng)制使用緩存
private(ngnix默認(rèn)): 只能被終端用戶(hù)的瀏覽器緩存截亦,不允許CDN等中繼緩存服務(wù)器對(duì)其緩存, 只有在第一次請(qǐng)求的時(shí)候才訪問(wèn)服務(wù)器, 若有max-age, 則緩存期間不訪問(wèn)服務(wù)器獲取資源爬泥,過(guò)期后才訪問(wèn)。
public: 可以被所有的用戶(hù)緩存崩瓤,包括終端用戶(hù)和CDN等中間代理服務(wù)器袍啡。
-
(3)協(xié)商使用緩存
no-cache
可以在客戶(hù)端存儲(chǔ)資源,不管本地緩存是否過(guò)期却桶,每次都必須去服務(wù)端做新鮮度校驗(yàn)境输,來(lái)決定從服務(wù)端獲取新的資源(200)還是使用客戶(hù)端緩存(304)。也就是所謂的協(xié)商緩存颖系。
must-revalidate
可以在客戶(hù)端存儲(chǔ)資源嗅剖,只有本地緩存過(guò)期才去服務(wù)端做新鮮度校驗(yàn)。
1嘁扼、不使用緩存
有時(shí)信粮,我們希望瀏覽器永遠(yuǎn)都不要使用緩存,全部到服務(wù)器拉取數(shù)據(jù)趁啸,此時(shí)即為不使用緩存强缘,我們可以在服務(wù)端通過(guò)Cache-Control為 no-store實(shí)現(xiàn)。
服務(wù)器端針對(duì)上面文件設(shè)置了no-store不傅,可以看到在請(qǐng)求的時(shí)候旅掂,無(wú)論怎么刷新,都是返回200访娶,不會(huì)顯示304商虐,也不會(huì)顯示“memory cache”或“disk cache”,說(shuō)明真的都是從服務(wù)器重新拉取數(shù)據(jù)。
比如我們想設(shè)置html文件不緩存称龙,可以在域名的解析配置中如下設(shè)置,當(dāng)文件后綴為html或htm時(shí)add_header Cache-Control “no-store”
server {
listen 80;
server_name yourdomain.com;
location / {
try_files $uri $uri/ /index.html;
root /yourdir/;
index index.html index.htm;
if ($request_filename ~* .*\.(?:htm|html)$)
{
add_header Cache-Control "no-store"; //對(duì)html文件設(shè)置永遠(yuǎn)不緩存
}
}
}
這種方式缺點(diǎn)就是每次都要去服務(wù)端拉取文件戳晌,即使文件沒(méi)有更新鲫尊,很明顯這樣增加了不必要的帶寬消耗。
如果文件沒(méi)有更新沦偎,我們就使用緩存疫向,只有更新了才去拉取最新文件,這樣多好豪嚎,這就是協(xié)商緩存搔驼。
2、協(xié)商緩存
協(xié)商緩存就是瀏覽器攜帶文件緩存標(biāo)識(shí)(如Last-Modified或ETag)侈询,向服務(wù)器發(fā)送請(qǐng)求舌涨,由服務(wù)器根據(jù)文件緩存標(biāo)識(shí)來(lái)決定是否使用緩存,如果文件沒(méi)有更新扔字,則告訴瀏覽器使用本地緩存囊嘉,如果文件更新了,則直接返回新文件內(nèi)容革为。
可以在服務(wù)端通過(guò)設(shè)置Cache-Control為 no-cache或者max-age=0來(lái)實(shí)現(xiàn)
可以看出扭粱,相比不使用緩存,協(xié)商緩存是會(huì)大大減少帶寬消耗的震檩。
- 協(xié)商緩存生效琢蛤,返回304 和 Not Modified
- 協(xié)商緩存無(wú)效,返回200和請(qǐng)求文件
我們?cè)跒g覽器調(diào)試頁(yè)面抛虏,可以看到有304的博其,即是使用了協(xié)商緩存
服務(wù)器返回的header中會(huì)有Last-Modified和ETag標(biāo)識(shí),而瀏覽器請(qǐng)求header中會(huì)包含If-Modified-Since和If-None-Match
LAST-MODIFIED和IF-MODIFIED-SINCE
在 http 1.0 版本中嘉蕾,第一次請(qǐng)求資源時(shí)服務(wù)器通過(guò) Last-Modified 來(lái)設(shè)置響應(yīng)頭的緩存標(biāo)識(shí)贺奠,并且把資源最后修改的時(shí)間作為值填入,然后將資源返回給瀏覽器错忱。在第二次請(qǐng)求時(shí)儡率,瀏覽器會(huì)首先帶上 If-Modified-Since 請(qǐng)求頭去訪問(wèn)服務(wù)器,服務(wù)器會(huì)將 If-Modified-Since 中攜帶的時(shí)間與資源修改的時(shí)間匹配以清,如果時(shí)間不一致儿普,服務(wù)器會(huì)返回新的資源,并且將 Last-Modified 值更新掷倔,作為響應(yīng)頭返回給瀏覽器眉孩。如果時(shí)間一致,表示資源沒(méi)有更新,服務(wù)器返回 304 狀態(tài)碼浪汪,瀏覽器拿到響應(yīng)狀態(tài)碼后從本地緩存數(shù)據(jù)庫(kù)中讀取緩存資源巴柿。
這種方式有2個(gè)弊端,第一個(gè)就是當(dāng)服務(wù)器中的資源增加了一個(gè)字符死遭,后來(lái)又把這個(gè)字符刪掉广恢,本身資源文件并沒(méi)有發(fā)生變化,但修改時(shí)間發(fā)生了變化呀潭。當(dāng)下次請(qǐng)求過(guò)來(lái)時(shí)钉迷,服務(wù)器也會(huì)把這個(gè)本來(lái)沒(méi)有變化的資源重新返回給瀏覽器;第二個(gè)就是修改時(shí)間的單位為秒钠署,所以存在1s的間隙糠聪,即使更新了,也會(huì)認(rèn)為沒(méi)有更新谐鼎。
ETAG和IF-NONE-MATCH
在 http 1.1 版本中舰蟆,服務(wù)器通過(guò) Etag 來(lái)設(shè)置響應(yīng)頭緩存標(biāo)識(shí)。Etag 的值由服務(wù)端生成狸棍,可以認(rèn)為是文件內(nèi)容的hash值夭苗。在第一次請(qǐng)求時(shí),服務(wù)器會(huì)將資源和 Etag 一并返回給瀏覽器隔缀,瀏覽器將兩者緩存到本地緩存數(shù)據(jù)庫(kù)题造。在第二次請(qǐng)求時(shí),瀏覽器會(huì)將 Etag 信息放到 If-None-Match 請(qǐng)求頭去訪問(wèn)服務(wù)器猾瘸,服務(wù)器收到請(qǐng)求后界赔,會(huì)將服務(wù)器中的文件標(biāo)識(shí)與瀏覽器發(fā)來(lái)的標(biāo)識(shí)進(jìn)行對(duì)比,如果不相同牵触,服務(wù)器返回更新的資源和新的 Etag 淮悼,如果相同,服務(wù)器返回 304 狀態(tài)碼揽思,瀏覽器讀取緩存
兩者對(duì)比
首先在精確度上袜腥,Etag要優(yōu)于Last-Modified。Last-Modified的時(shí)間單位是秒钉汗,如果某個(gè)文件在1秒內(nèi)改變了多次羹令,那么他們的Last-Modified其實(shí)并沒(méi)有體現(xiàn)出來(lái)修改,但是Etag每次都會(huì)改變確保了精度损痰;如果是負(fù)載均衡的服務(wù)器福侈,各個(gè)服務(wù)器生成的Last-Modified也有可能不一致。
第二在性能上卢未,Etag要遜于Last-Modified肪凛,畢竟Last-Modified只需要記錄時(shí)間堰汉,而Etag需要服務(wù)器通過(guò)算法來(lái)計(jì)算出一個(gè)hash值。
第三在優(yōu)先級(jí)上伟墙,服務(wù)器校驗(yàn)優(yōu)先考慮Etag
3翘鸭、強(qiáng)制緩存
有時(shí)我們希望文件強(qiáng)制使用緩存,比如通過(guò)vue-cli產(chǎn)生的js和css戳葵,文件名上帶有hash值矮固,所以如果文件名沒(méi)有變的時(shí)候,我們希望文件永久緩存譬淳,這樣可以減少網(wǎng)絡(luò)請(qǐng)求。
強(qiáng)制緩存整體流程比較簡(jiǎn)單盹兢,就是在第一次訪問(wèn)服務(wù)器取到數(shù)據(jù)之后邻梆,在過(guò)期時(shí)間之內(nèi)不會(huì)再去重復(fù)請(qǐng)求。實(shí)現(xiàn)這個(gè)流程的核心就是如何知道當(dāng)前時(shí)間是否超過(guò)了過(guò)期時(shí)間绎秒。
強(qiáng)制緩存的過(guò)期時(shí)間通過(guò)第一次訪問(wèn)服務(wù)器時(shí)返回的響應(yīng)頭獲取浦妄。在 http 1.0 和 http 1.1 版本中通過(guò)不同的響應(yīng)頭字段實(shí)現(xiàn)。
在 http 1.0 版本中见芹,強(qiáng)制緩存通過(guò) Expires 響應(yīng)頭來(lái)實(shí)現(xiàn)剂娄。 expires 表示未來(lái)資源會(huì)過(guò)期的時(shí)間。也就是說(shuō)玄呛,當(dāng)發(fā)起請(qǐng)求的時(shí)間超過(guò)了 expires 設(shè)定的時(shí)間阅懦,即表示資源緩存時(shí)間到期,會(huì)發(fā)送請(qǐng)求到服務(wù)器重新獲取資源徘铝。而如果發(fā)起請(qǐng)求的時(shí)間在 expires 限定的時(shí)間之內(nèi)耳胎,瀏覽器會(huì)直接讀取本地緩存數(shù)據(jù)庫(kù)中的信息(from memory or from disk),兩種方式根據(jù)瀏覽器的策略隨機(jī)獲取惕它。
在 http 1.1 版本中怕午,可以設(shè)置Cache-Control中的 max-age=xxx ,來(lái)表示緩存的資源將在 xxx 秒后過(guò)期淹魄。一般來(lái)說(shuō)郁惜,為了兼容,兩個(gè)版本的強(qiáng)制緩存都會(huì)被實(shí)現(xiàn)甲锡。
為什么有了Expires兆蕉,后來(lái)又增加了max-age呢,這是因?yàn)镋xpires是一個(gè)絕對(duì)時(shí)間缤沦,有可能客戶(hù)端的時(shí)間和服務(wù)器不一致恨樟,導(dǎo)致緩存不能按照預(yù)期進(jìn)行,而max-age則是個(gè)相對(duì)時(shí)間疚俱,比如3600s劝术,自瀏覽器請(qǐng)求后3600s之內(nèi),都使用本地緩存,和客戶(hù)端的時(shí)間沒(méi)關(guān)系养晋。
補(bǔ)充:
緩存的優(yōu)先級(jí)策略
-
文件緩存位置:
Service Worker 瀏覽器背后的獨(dú)立線程緩存
Memory Cache 瀏覽器內(nèi)存緩存
Disk Cache 系統(tǒng)硬盤(pán)緩存
Push Cache 推送緩存
具體可以看這里:
https://blog.csdn.net/weixin_43972437/article/details/105513486
打開(kāi)網(wǎng)頁(yè)衬吆,地址欄輸入地址:
查找 disk cache 中是否有匹配。如有則使用绳泉;如沒(méi)有則發(fā)送網(wǎng)絡(luò)請(qǐng)求逊抡。
普通刷新 (F5):
因?yàn)轫?yè)面tab并沒(méi)有關(guān)閉,因此 memory cache 是可用的零酪,會(huì)被優(yōu)先使用(如果匹配的話)冒嫡。其次才是 disk cache。
強(qiáng)制刷新 (Ctrl + F5):
瀏覽器不使用緩存四苇,因此發(fā)送的請(qǐng)求頭部均帶有 Cache-control: no-cache(為了兼容孝凌,還帶了 Pragma: no-cache)。服務(wù)器直接返回 200 和最新內(nèi)容月腋。
比如:訪問(wèn)圖片-> 200 -> 退出瀏覽器
再進(jìn)來(lái)-> 200(from disk cache) -> 刷新 -> 200(from memory cache)
-
緩存失效策略分類(lèi):
緩存過(guò)期時(shí)間 : Cache-control 的優(yōu)先級(jí)高于 Expires
文件是否改動(dòng)標(biāo)識(shí): Etag 的優(yōu)先級(jí)高于 Last-Modified
SPA應(yīng)用緩存解決方案
- 方案一:直接在index.html中加入了這幾行代碼:
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
缺點(diǎn):升級(jí)時(shí)緩存問(wèn)題倒解決了蟀架,但直接導(dǎo)致了用戶(hù)每次訪問(wèn)你的程序時(shí)都要重新請(qǐng)求服務(wù)器,所有的靜態(tài)資源都無(wú)法用緩存了榆骚,浪費(fèi)流量片拍,網(wǎng)絡(luò)壓力變大。且多數(shù)服務(wù)器不支持妓肢。
- 方案二:Nginx 配合 vue.config.js 進(jìn)行配置
由于打包后的js捌省、css和圖片,一般名稱(chēng)都帶有hash值碉钠,名稱(chēng)中的hash變了所禀,自然會(huì)拉取新文件,所以我們可以將這類(lèi)文件設(shè)置為強(qiáng)制緩存放钦,只要文件名不變色徘,就一直緩存,或者設(shè)置緩存比較久的時(shí)間100天或者一年操禀。
而html文件則不能設(shè)為強(qiáng)制緩存褂策,一般html名稱(chēng)是沒(méi)法帶hash值的,所以html如果設(shè)置了強(qiáng)制緩存颓屑,則永遠(yuǎn)也沒(méi)法更新斤寂,html不更新,其引用的js揪惦、css等名稱(chēng)也不會(huì)更新遍搞,則整個(gè)服務(wù)都沒(méi)有更新,只能讓用戶(hù)清除緩存了器腋。所以針對(duì)html文件溪猿,我們可以設(shè)置協(xié)商緩存或者直接不使用緩存钩杰。
nginx配置:
location /udaam-ui {
root /usr/local/ui-workspace;
index index.html index.htm;
try_files $uri $uri/ /udaam-ui/index.html;
if ($request_filename ~* .*\.(js|css|woff|png|jpg|jpeg)$){
expires 100d; #js、css诊县、圖片緩存100天
#add_header Cache-Control "max-age = 8640000"; #或者設(shè)置max-age
}
if ($request_filename ~* .*\.(?:htm|html)$){
add_header Cache-Control "no-cache, no-store"; #html不緩存
}
}
root:設(shè)置靜態(tài)根目錄為 data
index:設(shè)置目錄的默認(rèn)文件為 index.html 讲弄、index.htm
try_files:設(shè)置文件查找規(guī)則為 uri/ /index.html。即3個(gè)規(guī)則依痊,先從
uri/ 目錄中查找,最后查找 /index.html胸嘁。
vue.config.js設(shè)置:
修改output的filename和chunkFilename
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
return {
output: {
// 輸出重構(gòu) 打包編譯后的 文件名稱(chēng) 【模塊名稱(chēng).版本號(hào).時(shí)間戳】
filename: `js/[name].[chunkhash].js`,
chunkFilename: `js/[id].[chunkhash].js`
}
}
}
},
- filename 指列在entry 中瓶摆,打包后輸出的文件的名稱(chēng)。
- chunkFilename 指未列在entry 中性宏,卻又需要被打包出來(lái)的文件的名稱(chēng)群井。
修改打包后的css
css: {
extract: { // 打包后css文件名稱(chēng)添加時(shí)間戳
filename: `css/[name].[chunkhash].css`,
chunkFilename: `css/chunk.[id].[chunkhash].css`
}
}
原文地址:https://blog.csdn.net/qq_42268364/article/details/119386473
參考文章:http://www.reibang.com/p/5068788204f9