瀏覽器緩存,配置得當,它能讓頁面飛起來;配置錯了,一次小小的上線,就能把你扔進線上 bug 的坑里。你可能遇到過這些情況:
- 部署上線了,結果用戶還在加載舊的 JS;
- 接口數據改了,頁面卻還拿著幾分鐘前的老版本;
- Service Worker 緩了一大堆東西,結果連新頁面都加載不出來……
一、瀏覽器緩存到底是怎么一回事?
別被“緩存”兩個字騙了,它不只是簡單地“存一下資源”。
瀏覽器的緩存機制其實是分層的,而且各層的策略和觸發條件都不一樣:
1.1 三類緩存存儲層
緩存類型 | 生命周期 | 典型用途 |
Memory Cache | 頁面打開期間,關閉即清 | JS/CSS 快速復用 |
Disk Cache | 瀏覽器層面,長期有效 | HTML、圖片等 |
Service Worker Cache | 自定義、可離線 | PWA 場景或定制緩存策略 |
1.2 兩種核心緩存邏輯
瀏覽器判斷一個資源能不能用緩存,基本分這兩種邏輯:
? 強緩存(直接用,不發請求)
通過 HTTP 響應頭:
Cache-Control: max-age=31536000
或者:
Expires: Wed, 21 Oct 2025 07:28:00 GMT
只要瀏覽器還在有效期內,連請求都不發,直接從緩存取資源。
? 協商緩存(發請求,看是否要更新)
如果沒命中強緩存,瀏覽器會嘗試和服務器協商資源是否變了:
If-None-Match: "e1d3f...etag"
如果服務器返回 304,說明資源沒變,瀏覽器用本地緩存;否則重新拉。
二、常見“緩存坑”還原現場
🧨 場景一:JS 改了,用戶卻還是老頁面
怎么踩的?
前端用了默認打包配置,JS 文件名不變,瀏覽器命中了強緩存,用戶根本沒加載到新版資源。
怎么救?
- 打包輸出文件名加上 hash,比如:
app.3e9fbd.js
Vite/Webpack 都支持 [contenthash]
。
- 確保 HTML 不緩存!因為 HTML 決定了要加載哪個 JS 文件,如果 HTML 沒更新,JS 永遠也更新不了。
Cache-Control: no-store
- 如果用了 CDN,還要記得清緩存或者上版本號。
🧨 場景二:接口數據老是卡住,怎么刷新都不變?
怎么踩的?
很多時候是 GET 請求被瀏覽器或者中間代理緩存了。
比如:
GET /api/user/info
但服務端沒寫清楚 Cache-Control
,瀏覽器自動緩存了響應。
怎么救?
- 后端返回頭加上:
Cache-Control: no-cache, no-store, must-revalidate
- 前端請求的時候,給 URL 加時間戳,強制打破緩存:
fetch(`/api/user/info?_t=${Date.now()}`)
🧨 場景三:Service Worker 緩了個寂寞,更新根本不生效
怎么踩的?
你可能用了 Workbox 或手寫了 SW 緩靜態資源,但是沒處理好版本更新流程,結果用戶永遠在舊版本里打轉。
怎么救?
- 每次構建產出時更新 SW 文件里的版本號:
const CACHE_NAME = 'my-app-v2.0.1';
- 在
install
階段調用self.skipWaiting()
,跳過等待狀態。 - 在
activate
階段用clients.claim()
接管所有頁面。 - 頁面上監聽 SW 更新事件,給用戶提示“有新版本啦,點我刷新”。
三、前端緩存怎么設計才靠譜?
我們總結一個簡化但實用的資源緩存模型:
資源類型 | 緩存策略 | 原因 |
|
| 確保每次加載最新入口 |
JS/CSS(打包產物) |
| 文件名唯一,放一年都沒問題 |
圖片 / 字體 | CDN 強緩存 | 資源大且變化少 |
接口數據 |
/ 加時間戳 | 實時性要求高 |
PWA 離線資源 | SW 控制 | 手動緩存 + 可更新 |
四、工程化落地建議
別只靠腦子記,我們得把緩存策略寫進構建流程里:
4.1 打包配置文件指紋
Webpack/Vite:
output: {filename: '[name].[contenthash].js'
}
4.2 HTML 注入正確的資源引用
Webpack 用 HtmlWebpackPlugin
;Vite 自動處理。
4.3 CDN 清緩存腳本
比如:
npx aliyun-cdn-purge path/to/index.html
或者自動腳本 + Git Hook 聯動清緩存。
五、Service Worker
建議不要上來就用 SW 緩全站資源,除非你非常清楚它的行為。
常用策略:
- 圖片、靜態文件:Cache First
- 接口數據:Network First
- HTML 入口:Network Only
- 通知/消息等:Network Only + fallback
搭配 Workbox,配置如下:
workbox.routing.registerRoute(/\.(?:png|jpg|jpeg|svg)$/,new workbox.strategies.CacheFirst({cacheName: 'images',})
);
更新版本時,只需要更新緩存名,比如:
const CACHE_NAME = 'v2.0.3';
頁面監聽更新:
navigator.serviceWorker.onupdatefound = () => {// 顯示刷新提示
}
六、調試緩存的幾種方法
- Chrome DevTools → Network 里看資源的
Status
是不是(from disk cache)
或(from memory cache)
- 查看
Response Headers
是否有Cache-Control
、ETag
curl -I
直接看 HTTP 響應頭- Service Worker 狀態 → Chrome DevTools → Application → Service Worker
總結
瀏覽器緩存細節極多,尤其是前端更新策略和 CDN/服務器協作時,要明確方向:
- 明確哪些資源該緩存、緩存多久
- 更新機制清晰、可控、不怕上線
- 構建流程自動化,不靠人肉維護