瀏覽器預設快取行為不一,透過 HTTP 回應標頭可精確控制資源快取與否。本文詳細說明「禁用快取」與「啟用快取」兩種場景的標頭配置差異與代碼實現。
// 設定編碼
response.setContentType("text/html;charset=UTF-8");
// 禁用快取三大標頭
response.setHeader("Expires", "-1"); // 立即過期
response.setHeader("Cache-Control", "no-cache"); // HTTP/1.1 不快取
response.setHeader("Pragma", "no-cache"); // HTTP/1.0 相容
原理解析:
Expires: -1:過期時間設為過去,瀏覽器視為已過期。Cache-Control: no-cache:要求每次向伺服器驗證(可配合 must-revalidate)。Pragma: no-cache:舊版瀏覽器/代理相容。關鍵點:
setDateHeader 自動格式化為 GMT 時間(如 Wed, 21 Oct 2025 07:28:00 GMT)。max-age 優先級高於 Expires,建議兩者同時設定。public 允許 CDN/代理快取;private 僅瀏覽器快取(含用戶資訊頁面)。1000L 必須加 L,否則乘法溢位導致負數時間。@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("image/jpeg");
resp.setDateHeader("Last-Modified", System.currentTimeMillis());
resp.setDateHeader("Expires", System.currentTimeMillis() + 1000L * 3600 * 24 * 30);
resp.setHeader("Cache-Control", "public, max-age=2592000");
resp.setHeader("Pragma", "Pragma");
try (FileInputStream fis = new FileInputStream(getServletContext().getRealPath("/1.jpg"));
ServletOutputStream os = resp.getOutputStream()) {
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) os.write(buf, 0, len);
}
}

Last-Modified + If-Modified-Since:基於修改時間驗證。ETag + If-None-Match:基於內容指紋驗證(更精確,支援內容未變但時間變的情況)。ShallowEtagHeaderFilter 自動生成 ETag。| 資源類型 | 建議策略 |
|---|---|
| HTML 動態頁 | no-cache, no-store, must-revalidate |
| API JSON | no-cache(或短快取 + ETag) |
| 靜態資源 (v1.2.3.css) | 長快取 (1年) + 檔名含雜湊版本號 |
| 使用者頭像 | private, max-age=3600 + ETag |
精準的快取控制能大幅降低伺服器負載、提升頁面載入速度,是 Web 效能優化的第一道防線。