Spring MVC应用CSS/JS/JSP版本控制方案求助(兼容IE10)
解决IE10/Edge下静态资源与JSP缓存更新问题
结合你的技术栈(Spring MVC、WebLogic、AngularJS,用户仅用IE10和Edge),我给你几个经过验证的永久方案,彻底解决部署后缓存不更新的问题:
1. 修复版本号方案(快速见效,适合临时过渡)
你之前尝试的filename.js?version=2.1没生效,大概率是这几个环节没做到位:
- 动态生成版本号,而非硬编码:
不要手动写版本号,而是从项目构建配置(比如pom.xml的<version>)或者自动生成的文件哈希值获取,确保每次部署自动更新。在JSP里用EL表达式动态注入:
然后在Spring MVC的全局拦截器或者BaseController里,把版本号放入Model:<script src="${pageContext.request.contextPath}/js/app.js?v=${appVersion}"></script> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css?v=${appVersion}">@ControllerAdvice public class GlobalControllerAdvice { @ModelAttribute("appVersion") public String getAppVersion() { // 可以读取pom.xml版本,或者计算资源文件的哈希值 return "2.1.0"; // 实际项目中换成动态获取的版本/哈希 } } - 给JSP添加强制不缓存的响应头:
IE10对JSP的缓存特别顽固,直接在JSP头部加meta标签不够可靠,最好用过滤器全局控制:
先写一个过滤器类:
然后在web.xml中配置:public class NoCacheFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); chain.doFilter(req, res); } // init和destroy方法省略 }
这样所有JSP请求都会强制浏览器从服务器拉取最新内容,不会用本地缓存。<filter> <filter-name>NoCacheFilter</filter-name> <filter-class>com.yourcompany.filter.NoCacheFilter</filter-class> </filter> <filter-mapping> <filter-name>NoCacheFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
2. 内容哈希重命名资源(最可靠,推荐长期使用)
这是前端工程化的标准方案,核心是让文件名随内容变化,比如把app.js改成app.abc123.js(abc123是文件内容的MD5哈希),这样文件内容一修改,文件名就变,浏览器会自动认为是新资源,直接下载,完全不需要用户操作。
- 实现步骤:
- 用构建工具(Maven/Gradle插件、Gulp/Grunt等)在打包时自动给CSS/JS文件添加哈希后缀,并生成一个资源映射文件(比如
asset-manifest.json),记录原始文件名和哈希文件名的对应关系。 - 在Spring MVC中读取这个映射文件,在JSP引用资源时动态输出哈希后的文件名:
<script src="${pageContext.request.contextPath}/js/${manifest['app.js']}"></script> - 对于AngularJS的视图模板,同样给模板URL加上哈希后缀,或者直接用哈希后的文件名。
- 用构建工具(Maven/Gradle插件、Gulp/Grunt等)在打包时自动给CSS/JS文件添加哈希后缀,并生成一个资源映射文件(比如
- 这个方案完全兼容IE10,是解决缓存问题的终极方案,一旦配置好,后续部署再也不用管缓存问题。
3. WebLogic全局缓存配置(辅助优化)
在WebLogic的weblogic.xml中配置静态资源的缓存策略,确保服务器能正确通知浏览器资源已更新:
<container-descriptor> <!-- 每次请求都检查资源是否修改 --> <resource-reload-check-secs>0</resource-reload-check-secs> </container-descriptor> <cache-descriptor> <cache-mapping> <url-pattern>*.js</url-pattern> <!-- 私有缓存,禁止代理缓存 --> <cache-scope>private</cache-scope> <!-- 资源过期时间设为0,强制浏览器每次验证 --> <expires>0</expires> </cache-mapping> <cache-mapping> <url-pattern>*.css</url-pattern> <cache-scope>private</cache-scope> <expires>0</expires> </cache-mapping> </cache-descriptor>
这个配置能让WebLogic在资源更新后,返回304 Not Modified或者新资源,配合前面的方案使用,效果更好。
4. AngularJS模板缓存处理
因为你用ng-if渲染视图,AngularJS默认会把模板缓存到$templateCache里,即使服务器端模板更新了,AngularJS可能还在用旧缓存。解决办法:
- 在路由配置中给模板URL添加动态版本/哈希参数:
angular.module('myApp').config(['$routeProvider', function($routeProvider) { var version = '${appVersion}'; // 从JSP传入的版本号 $routeProvider.when('/view1', { templateUrl: '/views/view1.html?v=' + version, controller: 'View1Controller' }); }]); - 或者在应用启动时,主动清除模板缓存并重新加载:
angular.module('myApp').run(['$templateCache', '$http', function($templateCache, $http) { var version = '${appVersion}'; // 清除旧缓存 $templateCache.removeAll(); // 重新加载模板并缓存 $http.get('/views/view1.html?v=' + version, {cache: $templateCache}); // 其他模板同理 }]);
总结一下,优先推荐内容哈希重命名资源的方案,这是一劳永逸的解决办法。如果暂时没法改造构建流程,先从修复版本号和JSP缓存控制入手,也能解决大部分问题。
内容的提问来源于stack exchange,提问作者Praveen Kumar
相关产品推荐
相关产品推荐

