開發階段頻繁修改 JS/CSS,瀏覽器強緩存導致「明明改了代碼頁面卻不生效」是常見痛點。本文提供一個通用 Filter 方案:攔截 `.js`/`.css` 請求,自動在 URL 追加時間戳參數(`__oawx_t=timestamp`),強制瀏覽器重新獲取最新資源,無需手動清理緩存或修改 HTML 引用。
public class StaticResourceCacheFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(StaticResourceCacheFilter.class);
private static final String STATIC_TAIL = "__oawx_t=";
@Override
public void init(FilterConfig filterConfig) { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String requestURL = req.getRequestURL().toString();
String queryStr = req.getQueryString();
// 僅攔截 .js / .css 靜態資源
if (requestURL != null && (requestURL.endsWith(".js") || requestURL.endsWith(".css"))) {
String newURL = null;
// 情況 1:已有查詢參數,且無時間戳參數 → 追加 &__oawx_t=timestamp
if (StringUtils.isNotBlank(queryStr) && !queryStr.contains(STATIC_TAIL)) {
newURL = requestURL + "?" + queryStr + "&" + STATIC_TAIL + System.currentTimeMillis();
}
// 情況 2:無查詢參數 → 直接加 ?__oawx_t=timestamp
else if (StringUtils.isBlank(queryStr)) {
newURL = requestURL + "?" + STATIC_TAIL + System.currentTimeMillis();
}
// 需要重定向時執行 302 跳轉
if (newURL != null) {
resp.sendRedirect(newURL);
return; // 終止後續 Filter 鏈
}
}
// 非靜態資源或已帶時間戳,正常放行
try {
chain.doFilter(request, response);
} catch (Exception e) {
log.error("Filter chain error", e);
}
}
@Override
public void destroy() { }
}
public class ParameterConfig {
/** 靜態資源防緩存時間戳參數名 */
public static final String STATIC_TAIL = "__oawx_t=";
}
<filter>
<filter-name>staticCacheFilter</filter-name>
<filter-class>com.yourpkg.StaticResourceCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>staticCacheFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 攔截所有請求,Filter 內部判斷後綴 -->
</filter-mapping>
原請求:GET /static/app.js?v=1.0
重定向後:GET /static/app.js?v=1.0&__oawx_t=1705574400123

| 維度 | 說明 |
|---|---|
| 原理 | URL 變化 → 瀏覽器視為新資源 → 繞過強緩存(Cache-Control: max-age)直接向伺服器請求 |
| 優點 | 零侵入業務代碼、無需修改 JSP/HTML 引用、開發環境自動生效、生產可關閉 Filter |
| 缺點 | 每次請求觸發 302 重定向,增加一次網路往返;生產環境必須關閉,否則影響緩存效能 |
| 適用場景 | 開發/測試環境;生產環境請改用構建工具(Webpack/Vite)生成內容哈希文件名(如 app.a1b2c3.js) |
| 方案 | 環境 | 原理 | 維護成本 |
|---|---|---|---|
| Filter + 時間戳 | 開發/測試 | URL 參數變化 | 零配置,自動生效 |
| 構建工具 Hash 文件名 | 生產 | 文件名含內容哈希(app.[hash].js) | 需構建流程支援,長期有效 |
Nginx add_header Cache-Control no-cache | 開發/特定目錄 | 響應頭禁用緩存 | 需運維配置,影響所有資源 |
| HTML `` | 頁面級 | 頁面元標籤 | 僅影響 HTML 文檔本身,不影響 JS/CSS |
提醒:上線前務必在web.xml註釋掉該 Filter,或通過 Spring Profile 僅在dev環境啟用,避免生產環境緩存失效導致流量暴增。