一:需求
頁面打包上傳到服務器后,用戶能在自己電腦上立即感知到更新
二:需求分析
調(diào)研后得知:
1.靠瀏覽器緩存,各種catche啥的不靠譜. -----pass,緩存不會那么快生效
2.頁面JS定時去查詢服務器保存版本號的文件,查看版本號是否過期
---pass,效率太差,如果有十萬用戶,每個用戶五分鐘去服務器查詢一次,服務器每
五分鐘被查詢五十萬次.
三:實現(xiàn)方案
前端接口請求http-header 攜帶時間戳版本號,后端比對時間戳版本號.
如果請求帶過來的時間戳小于服務器保存的,返回版本號過期錯誤.
如果請求帶過來的時間戳大于服務器保存的時間戳,更新服務器時間戳版本號.
同時,如果請求沒帶版本號參數(shù),則不對版本號進行校驗,方便dev環(huán)境前端開發(fā).
前端最好能自動生成版本號,自動更新,不用手動填值.
如果版本號過舊就執(zhí)行JS代碼location.reload(true),但是上線后有的人的瀏覽器
執(zhí)行了location.reload(true) 或者ctrl+f5,有可能部分文件還是走的緩存.
所以彈窗讓用戶選擇更新還是取消.如果選取消就清空版本號,后端不校驗空的就行
四:具體代碼應用
樣例代碼為vue2+webpack. 主要都是JS代碼. vue3和react也可以參考
第一步修改 入口文件
在入口文件index.html創(chuàng)建一個同級別JS文件config.js
在index.html引入這個文件
<script src="config.js?version=123456789"></script>
index.html引入文件后面有個后綴?version=123456789,為什么要帶這個后綴呢?
因為不帶部分瀏覽器會給你緩存了,哪怕用戶ctrl+f5也不行,只能手動清理緩存.
這個后綴的數(shù)字123456789每次打包后都會被修改,為了方便就修改成版本號
第二步 創(chuàng)建config.js
代碼如下,里面代碼不重要,主要起到模板記錄作用,因為每次打包會重新生成.
主要意思就是讀取版本號變量timestamp 的值,并存入localStorage中,
這樣接口請求的時候可以從localStorage讀取timestamp 的值放到head帶給后端.
let timestamp = 1693386173000
if(localStorage.timestamp){
if(timestamp < localStorage.timestamp){
console.log('timestamp is small')
}else{
console.log('timestamp is big')
localStorage.timestamp = timestamp
}
}else{
localStorage.timestamp = timestamp
}
console.log('configjs read again')
上面代碼除了注釋可以刪,每一行都有用,謹慎修改
3.修改vue.config.js
我們要在輸入npm run build打包命令后,進行操作
引入node的文件函數(shù),能讀取文件
const fs = require("fs");
// 判斷是否為生產(chǎn)環(huán)境
const isProd = process.env.NODE_ENV === "production";
然后在plugins下面放入同級函數(shù)
const Timestamp = new Date().getTime(); //時間戳
if (isProd) {
fs.readFile("./public/config.js", "utf8", function(err, data) {
if (err) {
console.log(err)
return
}
// console.log(data)
try {
// data = data.replace('1693971026219',Timestamp)
data = "";
let c_1 = " let timestamp = " + Timestamp;
console.log("c_1", c_1);
data = c_1 + "\n" + data;
let c_3 = "\n"+"console.log('configjs read again')"
let c_4 = `
if(localStorage.timestamp){
if(timestamp < localStorage.timestamp){
console.log('timestamp is small')
}else{
console.log('timestamp is big')
localStorage.timestamp = timestamp
}
}else{
localStorage.timestamp = timestamp
}
`
data = data +"\n"+String(c_4) + c_3
console.log('result_data',data)
} catch (err2) {
console.log(err2);
}
fs.writeFile("./public/config.js", data, function(err) {
if (err) {
console.log(err)
}
console.log("configjs文件已修改");
});
});
fs.readFile("./public/index.html", "utf8", function(err, data_2) {
if (err) {
console.log(err)
return
}
// console.log(data)
try {
data_2 = data_2.replace('123456789',Timestamp)
} catch (err2) {
console.log(err2);
}
fs.writeFile("./public/index.html", data_2, function(err) {
if (err) {
console.log(err)
}
console.log("html文件已修改");
// console.log("data_2",data_2)
});
});
}
該函數(shù)主要兩個作用:
一是修改config.js文件,把里面的timestamp值換成最新的時間戳值
二是修改index.html文件,把config.js?version=123456789的后綴123456789換成時間戳,避免瀏覽器緩存
第三步 vue實例綁定彈窗
這步不是必須的,因為要在axios的配置文件攔截響應,如果報版本號過期,要彈窗提示用戶是否更新頁面.
博主用的UI組件是antdvue 1.X,如果想在JS文件用vue的彈窗插件,需要先把這個彈窗插件綁定在vue實例上.
所以在app.vue執(zhí)行如下操作,給vue實例加個彈窗綁定.
彈窗記得要JS防抖.
mounted(){
// console.log('app vue')
// console.log(this.$confirm)
Vue.$confirm = this.$confirm
}
第四步 校驗版本號
和后端約定,如果版本號舊了,在返回的data對象里code屬性報402.
在axios的配置文件,相應攔截回調(diào)函數(shù)里配置402錯誤對應的執(zhí)行代碼.
記得按照你和后端的約定修改代碼
response => {
if (
response.data.code != 200 &&
response.request.responseType != "arraybuffer" &&
response.data.info !== "成功"
) {
//版本舊了
if (response.data.code == 402) {
console.log('行為分析 接口報402 錯誤碼')
// location.reload(true)
if (timer_request) {
clearTimeout(timer_request)
}
timer_request = setTimeout(() => {
console.log(88945)
// localStorage.timestamp = ''
// location.reload(true)
Vue.$confirm({
title: '檢測到新版本,是否立即更新頁面?',
content: h =>(
<div style="">
點擊取消,后續(xù)將不再檢測版本,
除非手動更新頁面或者等待瀏覽器自動更新緩存后才繼續(xù)檢測
</div>
) ,
onOk() {
console.log('OK');
localStorage.timestamp = ''
location.reload(true)
},
onCancel() {
console.log('Cancel');
localStorage.timestamp = ''
},
});
}, 4000)
}
return response;
}
return response;
},
第五步 打包上線
1.如果你是自動部署,比如把代碼提交到git,jekines自動部署,代碼直接提上去就行
2.如果你是本機打包好后,手動把打包文件傳到服務器部署.
那么每次執(zhí)行打包操作,你的index.html和config.js都會被修改,生成打包文件后記得還原下