手摸手教你解決重定向快取問題
問題產生:
測試粑粑:測試環境已經搭好了,前端打個包吧!
weber:好嘞!快速輸入命令:npm run build:stagging
三分鐘後……
測試粑粑:是不是打錯包了?怎麼還沒變?
weber:重新整理下頁面試試!
測試粑粑:沒用鴨~
weber:蛤~清理下瀏覽器快取!
測試粑粑:出來了,**牛皮鴨!!!
問題到這裡,我陷入了沉思,咋回事呢,如果每次釋出需要使用者手動清除瀏覽器快取,這無疑是一個巨大的bug?於是開始列出了問題排查清單:
1、重新整理頁面重新進行了doc【index.html】請求,無效;而清理瀏覽器快取缺生效了,說明瀏覽器快取了檔案導致重新整理請求時還是之前的檔案。
2、webpack打包時,output給js、css加上了hash,那js、css應該就不會快取。
開始排查
一、檢查了webpack打包配置:
module.exports = {
context : path.join(__dirname,'src'),
entry:{
main: './index.js',
vender:['./jquery.js','./test.js']
},
module:{
rules:[{
test:/\.css$/,
use: extractTextPlugin.extract({
fallback:'style-loader',
use:'css-loader'
})
}]
},
output:{
path:path.join(__dirname, '/dist/js'),
filename: 'bundle.[name].[hash].js',
},
plugins:[
new extractTextPlugin('../css/bundle.[name].[hash].css')
]
}
複製程式碼
發現webpack打包沒有問題。
二、打包後的檔案也沒有問題。
三、打包後生成的index.html檔案引入。
三、檢視network請求才恍然大悟:
index.html是304請求,那說明index.html被快取了。
解決問題
開始尋找解決辦法,方法有很多,有前端配置的,也有後端配置的。
考慮到webpack打包生成的html只是作為引入js、css的容器,若只是不快取html檔案,代價其實很小。選擇如下方法:
1、在html head頭部新增不快取html配置:
注:meta是tml語言head區的一個輔助性標籤,其中的http-equiv欄位定義了伺服器和使用者代理的一些行為。在之前的規範中,meta的http-equiv欄位中有以下值與http header快取相關的欄位功能類似
<head>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
複製程式碼
若採用這種方式,請在public檔案加下的index.html配置。
2、修改nginx.conf,增加add_header Cache-Control 'no-cache, no-store, must-revalidate'不快取html配置:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location ~* \.(gif|jpg|jpeg|png|css|js|ico|eot|otf|fon|font|ttf|ttc|woff|woff2)$ {
expires 1M;
add_header Cache-Control "public";
}
location / {
add_header Cache-Control 'no-cache, no-store, must-revalidate';
}
error_page 404 /index.html;
}
複製程式碼
其實這兩個配置都是在請求head加上不快取html的配置,一個在前端,一個在運維。翻閱w3c文件發現,但現在w3c的規範欄位中這些值已經被移除,一個很好的理由是:
Putting caching instructions into meta tags is not a good idea, because although browsers may read them, proxies won't. For that reason, they are invalid and you should send caching instructions as real HTTP headers.
綜合之後還是第二種方案較為完善。
bug再現:
weber:這次修改了nginx配置,這次打包應該不會出現上次的快取問題了,不用手動清楚瀏覽器快取了!
測試粑粑:牛皮鴨,我試試~
weber:(自信的小表情,期待的小紅手)~
測試粑粑:還是有問題鴨!還是沒更新過來!
weber:你是直接請求是吧?有沒有重新整理頁面?
測試粑粑:沒有,直接請求的~
weber:好了,我知道了!
問題到這裡,又出現了bug。如果直接請求網址,是會請求到最新的html檔案,但是還會存在使用者不重新整理直接請求的情況。
理清思路:
其實到這一步問題已經很清晰了,重新理一遍webpack打包過程、瀏覽器快取策略,問題就很容易解決了。
一、webpack打包:
public/index.html:檔案是一個會被 html-webpack-plugin 處理的模板。在構建過程中,資源連結會被自動注入。另外,Vue CLI 也會自動注入 resource hint (preload/prefetch、manifest 和圖示連結 (當用到 PWA 外掛時) 以及構建過程中處理的 JavaScript 和 CSS 檔案的資源連結。ouput裡面的檔案都會inject
二、HTTP重定向:
伺服器的nginx配置如下:假若輸入:https://example.com,https://example.com/a都會定位到root下的index.html檔案,也會觸發請求html檔案。
三、瀏覽器快取:
再次檢視增加了不快取html檔案,請求狀態變成了200。
因此,在不重新整理瀏覽器的情況下請求,html是沒有被請求的,仍然是第一次輸入網址請求回來的html檔案,裡面的js、css也是之前的,所以瀏覽器不會再去請求js、css檔案。解決辦法:
在axios請求加上版本號,如果版本號對應不上,則返回code,讓前端去與使用者互動是否已經更新了,需要重新整理頁面。