一.場景需求
使用者在使用我們的web項目的時候,由于有時候會有生産環境的更新,如果使用者在更新前就加載了網頁,更新之後使用者沒有重新整理的話偶爾會導緻頁面報錯,這種往往我們提示使用者重新整理一下就好了,不屬于業務或者代碼層面的錯誤。近期由于多次出現這種情況,故老大叫我解決一下。
二.解決思路
做版本号管理,每次調用接口的時候做一次版本校驗,如果校驗通過則正常通路接口,如果校驗不通過就傳回特殊狀态碼前端自動做一次重新整理頁面以擷取最新的頁面靜态資源。
三.實作
首先,需要每次打包的時候将版本号變動起來,也就是自動去更改版本号,這裡通過打包時執行一段js的方式來實作
package.json
{
"name": "project",
"version": "0.0.11",
"lastBuildTime": "2023-02-24 17:28:52",
"scripts": {
"dev": "vite",
"start": "vite",
"build": "vite build --mode=production",
"build:auto": "node ./myBuild.js && vite build --mode=production",
"build:stag": "vite build --mode=staging",
"serve": "vite preview"
}
}
myBuild.js
const fs = require("fs")
const dayjs = require("dayjs")
const axios = require("axios")
// 建構版本号的函數,這裡隻簡單做下遞增,後面可以優化成每建構一定次數的版本之後幾句自動給二級版本号加1
const versionGenerrator = (version) => {
let newVersion = Number(version[2]);
console.log([version[0], version[1], ++newVersion].join("."));
return [version[0], version[1], ++newVersion].join(".");
};
// 設定版本号--傳入版本号并儲存至資料庫,本地也重新生成package.json的檔案
const setVersion = (version) => {
// 構造傳入後端接口的參數
let data = {
id: 59,
paramKey: "version_web",
paramValue: version,
};
try {
axios
.post(
"https://gateway.xxxxxxx.com/platform/config/updateByKey",
data,
{
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
}
)
.then((response) => {
if (response.data?.code == 200 && response.data?.data == 1) {
console.log("檔案版本号修改成功,開始寫入本地檔案");
packageJson.version = version;
packageJson.lastBuildTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
fs.writeFile(
"./package.json",
JSON.stringify(packageJson, null, "\t"),
(err) => {
if (err) {
console.log("寫入檔案失敗,請檢查是否擁有檔案夾權限", err);
} else {
console.log("檔案寫入成功-->" + packageJson.lastBuildTime);
}
}
);
}
});
} catch (error) {
console.log("版本号寫入接口失敗,已停止");
}
};
// 先讀取package.json
let packageJson = JSON.parse(fs.readFileSync("./package.json"));
// 建構新的版本号
let version = versionGenerrator(packageJson.version.split("."));
// 調用接口設定到後端并且聲成新的package.json
setVersion(version);
到這裡就已經實作了版本号自動變更送出到伺服器,接下來就是每次調用接口對這個版本号進行校驗,我選擇的是直接将校驗的動作放在網關上面,校驗不通過的時候就傳回一個505的狀态碼。前端需要做的就是在調用接口的時候将目前的版本号放在headers裡面,這個操作就放在咱們已經封裝好的axios請求攔截器跟響應攔截器上面了
// 請求攔截
service.interceptors.request.use(
(config) => {
// JWT鑒權處理
if (store.getters["user/token"]) {
config.headers["Token"] = store.state.user.token;
}
config.headers["version_web"] = version; //版本号,從package.json中引入
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 響應攔截
service.interceptors.response.use(
(response) => {
if(response.code==505){
ElMessage.error("檢查到版本号不一緻自動重新整理頁面");
setTimeout(() => {
window.location.reload();
}, 3000);
}
}
);
這裡就完全實作了這個功能了,客戶浏覽器如果加載的是0.0.1版本的靜态檔案,資料庫裡面的版本号是0.0.2,調用接口就會傳回505并且自動重載頁面。不過後面跟我們後端的架構讨論,他認為這種實作方式對後端的開銷太大了,說是最好使用釋出訂閱模式,我不是很清楚這種場景怎麼去做訂閱,也不知道市面上主流的解決方案是什麼我想到了這種方式就用這種方式來實作了。如果有懂的小夥伴請一定要私信我,有償求助。