開發階段頻繁修改前端靜態資源(JS、CSS),瀏覽器強快取導致讀取舊版本是常見痛點。透過一個簡單的 Servlet Filter,在請求 URL 末尾自動附加時間戳參數,即可強制瀏覽器重新下載最新檔案。
public class StaticResourceTimestampFilter implements Filter {
private static final String TIMESTAMP_PARAM = "__ts=";
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String requestURL = request.getRequestURL().toString();
String queryString = request.getQueryString();
// 僅攔截 .js 與 .css 請求
if (requestURL.endsWith(".js") || requestURL.endsWith(".css")) {
StringBuilder newURL = new StringBuilder(requestURL);
if (queryString != null && !queryString.contains(TIMESTAMP_PARAM)) {
newURL.append('?').append(queryString).append('&').append(TIMESTAMP_PARAM).append(System.currentTimeMillis());
} else if (queryString == null || queryString.isEmpty()) {
newURL.append('?').append(TIMESTAMP_PARAM).append(System.currentTimeMillis());
} else {
// 已有時間戳參數,直接放行
chain.doFilter(request, response);
return;
}
// 重導向至新 URL,瀏覽器將視為新資源發起請求
response.sendRedirect(newURL.toString());
return;
}
chain.doFilter(request, response);
}
@Override public void init(FilterConfig config) {}
@Override public void destroy() {}
}
<filter>
<filter-name>staticTimestampFilter</filter-name>
<filter-class>com.example.filter.StaticResourceTimestampFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>staticTimestampFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
原請求:/assets/js/main.js
重導向後:/assets/js/main.js?__ts=1715000000000
每次請求參數不同,瀏覽器不會命中快取,始終獲取最新版本。上線前只需在 web.xml 移除或停用此 Filter,即可恢復正常快取策略,零侵入業務代碼。
Cache-Control、ETag 或檔名雜湊(如 main.a1b2c3.js)實現長效快取。