简体   繁体   English

防止JavaScript文件的浏览器缓存的更好方法

[英]Better way to prevent browser caching of JavaScript files

This is how we prevent caching of JS and CSS files by browsers. 这就是我们如何防止浏览器缓存JS和CSS文件。 This seems slightly hacky.. is there a better way? 这似乎有点hacky ..有更好的方法吗?

<%
//JSP code
long ts = (new Date()).getTime(); //Used to prevent JS/CSS caching
%>

<link rel="stylesheet" type="text/css" media="screen" href="/css/management.css?<%=ts %>" />
<script type="text/javascript" src="/js/pm.init.js?<%=ts %>"></script> 
<script type="text/javascript" src="/js/pm.util.func.js?<%=ts %>"></script> 

Update: The reason we want to prevent caching is to ensure the newer version of the files are loaded when we do a new release. 更新:我们想要阻止缓存的原因是为了确保在我们执行新版本时加载更新版本的文件。

You want CSS and JS to be cached. 您希望缓存CSS和JS。 It speeds up the loading of the web page when they come back. 当它们返回时,它加速了网页的加载。 Adding a timestamp, your user's will be forced to download it time and time again. 添加时间戳,您的用户将被迫一次又一次地下载它。

If you want to make sure they always have a new version, than have your build system add a build number to the end of the file instead of a timestamp. 如果要确保它们始终具有新版本,请使构建系统在文件末尾添加内部版本号而不是时间戳。

If you have issues with it just in dev, make sure to set up your browsers to not cache files or set headers on your dev pages to not cache. 如果您只是在dev中遇到问题,请确保将浏览器设置为不缓存文件或将开发页面上的标题设置为不缓存。

Caching is your friend. 缓存是你的朋友。 If browsers are caching these files incorrectly, it means something is wrong with the HTTP headers your web server is sending along with the JS and CSS files themselves (not the HTML page that uses them). 如果浏览器错误地缓存这些文件,则表示Web服务器与JS和CSS文件本身(而不是使用它们的HTML页面)一起发送的HTTP标头出现问题。 The browser uses those headers to figure out if it can cache the file. 浏览器使用这些标头来确定它是否可以缓存文件。

Your Web server can send these headers (on every JS and CSS file it serves) to tell browsers not to cache them: 您的Web服务器可以发送这些标头(在它所服务的每个JS和CSS文件上),告诉浏览器不要缓存它们:

Cache-Control: no-cache
Pragma: no-cache
Expires: Sat, 01 Jan 2000 00:00:00 GMT

But that will increase the network load on your site, and users will see the page load slower. 但这会增加您网站的网络负载,用户会看到网页加载速度变慢。 You could be a little more lenient and allow the browser to cache the CSS file for 60 seconds: 您可以稍微宽松一点,并允许浏览器缓存CSS文件60秒:

Cache-Control: max-age=60

If you really want the browser to check for a new file with every single page load, you can still save some network traffic by using an ETag: 如果您确实希望浏览器检查每个页面加载的新文件,您仍然可以使用ETag来节省一些网络流量:

Cache-Control: max-age=0
Pragma: no-cache
Expires: Sat, 01 Jan 2000 00:00:00 GMT
ETag: "o2389r-98ur0-w3894tu-q894"

The ETag is simply a unique identifier your Web server makes up each time the file changes. ETag只是每次文件更改时Web服务器组成的唯一标识符。 The next time the browser wants the file, it asks the server, "does /js/pm.init.js still have the ETag o2389r98ur0w3894tuq894?" 下次浏览器需要该文件时,它会询问服务器“/js/pm.init.js是否还有ETag o2389r98ur0w3894tuq894?” and if so, your server simply says, "yes". 如果是这样,你的服务器只是说“是”。 That way your server doesn't have to send the whole file again, and the user doesn't have to wait for it to load. 这样,您的服务器不必再次发送整个文件,用户不必等待它加载。 Win-win. 双赢。

How to convince your web server to autogenerate ETags depends on the server. 如何说服您的Web服务器自动生成ETag取决于服务器。 It's usually not hard. 这通常不难。

I've seen the hack you're using before. 我见过你之前使用的黑客。 Like so much on the Web, it's not pretty or particularly efficient, but it works. 就像在网上这么多,它不漂亮或特别有效,但它的工作原理。

If The reason we want to prevent caching is to ensure the newer version of the files are loaded when we do a new release. 如果我们想要阻止缓存的原因是确保在我们执行新版本时加载更新版本的文件。 , you want that the new js is loaded when THERE IS a NEW release, not all the times. ,你想要在新版本发布时加载新的js,而不是所有的时间。

In order to do that you want that the "ts" value is linked with the file not with the time of the day. 为了做到这一点,你希望“ts”值与文件链接而不是与一天中的时间相关联。 You can either use one of these system: 您可以使用以下系统之一:

  1. ts = Timestamp OF THE FILE ts =文件的时间戳
  2. ts = MD5 (or whatever checksum) of the FILE ts =文件的MD5(或任何校验和)
  3. ts = version of the code. ts =代码的版本。 If you have a script that do deployment be sure that it adds the version code (or the date of the release) in some include file that will be assigned to ts. 如果您有一个执行部署的脚本,请确保它在一些将分配给ts的包含文件中添加版本代码(或发布日期)。

In this way the browser will reload the file only if it is new and not all the times. 通过这种方式,浏览器将仅在新文件时重新加载文件,而不是所有时间。

A simple approach to this would be to use last modified date of the js or css files in the URL instead of a time stamp. 一种简单的方法是使用URL中js或css文件的最后修改日期而不是时间戳。 This would have the effect of preventing caching only when there is a new version of the file on the server. 只有当服务器上有新版本的文件时,这才能防止缓存。

Edit 编辑

In case you are using Spring Boot it's now much simpler to prevent caching of modified files. 如果您使用的是Spring Boot,现在可以更加简单地防止对已修改文件进行缓存。

All you need to do is add this to application.properties: 您需要做的就是将其添加到application.properties:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

If you are using Thymeleaf or FreeMarker it's completely autoconfigured. 如果您使用的是Thymeleaf或FreeMarker,它将完全自动配置。 If you are using JSPs you need to manually declare a ResourceUrlEncodingFilter. 如果您使用的是JSP,则需要手动声明ResourceUrlEncodingFilter。

Read more here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content 在这里阅读更多内容: http//docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content

What follows now is my "old" post which also works but requires more work. 接下来是我的“旧”帖子,它也有效但需要更多的工作。


Since you are using Java there is a chance you are also using maven to manage your project. 由于您使用的是Java,因此您也有可能使用maven来管理项目。

In that case, to improve performance, and to make sure that no browser caches your static resources when a new release of your software is produced, you should combine all of your stylesheets and JavaScript files into on single file of their type, and you should make your resource urls change when you create a new release. 在这种情况下,为了提高性能,并确保在生成新版软件时没有浏览器缓存静态资源,您应该将所有样式表和JavaScript文件合并到其类型的单个文件中,并且您应该创建新版本时,请更改资源URL。

Luckily maven can do all this for you at build-time. 幸运的是,maven可以在构建时为您完成所有这些工作。 You'll need minify-maven-plugin and maven-replacer-plugin . 你需要minify-maven-pluginmaven-replacer-plugin

This excerpt of a pom.xml should get you started: 这段pom.xml的摘录应该让你开始:

<properties>
    <timestamp>${maven.build.timestamp}</timestamp>
    <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
</properties>

<plugin>
    <groupId>com.samaxes.maven</groupId>
    <artifactId>minify-maven-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>minify-css</id>
            <phase>process-resources</phase>
            <goals>
                <goal>minify</goal>
            </goals>
            <configuration>
                <linebreak>-1</linebreak>
                <cssSourceDir>resources/css</cssSourceDir>
                <cssSourceFiles>
                    <cssSourceFile>bootstrap.css</cssSourceFile>
                    <cssSourceFile>style.css</cssSourceFile>
                </cssSourceFiles>
                <cssTargetDir>resources/css</cssTargetDir>
                <cssFinalFile>${timestamp}.css</cssFinalFile>
            </configuration>
        </execution>
        <execution>
            <id>minify-js</id>
            <phase>process-resources</phase>
            <goals>
                <goal>minify</goal>
            </goals>
            <configuration>
                <linebreak>-1</linebreak>
                <jsSourceDir>resources/js</jsSourceDir>
                <jsSourceFiles>
                    <jsSourceFile>jquery.js</jsSourceFile>
                    <jsSourceFile>bootstrap.js</jsSourceFile>
                    <jsSourceFile>script.js</jsSourceFile>
                </jsSourceFiles>
                <jsTargetDir>resources/js</jsTargetDir>
                <jsFinalFile>${timestamp}.js</jsFinalFile>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.2</version>
    <executions>
        <execution>
            <id>replaceDynPartInResourcePath</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
            <configuration>
                <ignoreMissingFile>false</ignoreMissingFile>
                <basedir>${project.build.directory}</basedir>
                <file>${project.artifactId}/WEB-INF/views/header.jsp</file>
                <regex>false</regex>
                <replacements>
                    <replacement>
                        <token>$dynamicResourceNamePart$</token>
                        <value>${timestamp}</value>
                    </replacement>
                </replacements>
            </configuration>
        </execution>
    </executions>
</plugin>

This is how to include your static resources in header.jsp 这是如何在header.jsp中包含静态资源

<c:choose>
    <c:when test="${not fn:contains(pageContext.request.serverName, 'localhost') and empty param.nocombine}">
        <link href="${pageContext.request.contextPath}/resources/css/$dynamicResourceNamePart$.min.css" rel="stylesheet" type="text/css" />
        <script src="${pageContext.request.contextPath}/resources/js/$dynamicResourceNamePart$.min.js" type="text/javascript"></script>
    </c:when>
    <c:otherwise>
        <link href="${pageContext.request.contextPath}/resources/css/bootstrap.css" rel="stylesheet">
        <link href="${pageContext.request.contextPath}/resources/css/style.css" rel="stylesheet">
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/jquery.js"></script>
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/bootstrap.js"></script>
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/script.js"></script>
    </c:otherwise>
</c:choose>

For debug purposes, install the web developer toolbar for FireFox and activate there "deactivate Cache" 出于调试目的,安装FireFox的Web开发人员工具栏并激活“停用缓存”

Update: 更新:
When you have FireBug installed, you can disable caching as well in the network tab settings . 安装FireBug后,您也可以在网络选项卡设置中禁用缓存

If you can include Java Servlet Filter in your application, here is a working solution: CorrectBrowserCacheHandlerFilter.java 如果您可以在应用程序中包含Java Servlet Filter,那么这是一个可行的解决方案: CorrectBrowserCacheHandlerFilter.java

Basically, when your browser requests the static files, the server will redirect every requests to the same one but with a hash query parameter ( ?v=azErT for example) which depends on the content of the target static file. 基本上,当您的浏览器请求静态文件时,服务器会将每个请求重定向到同一个请求,但使用哈希查询参数(例如?v=azErT ),这取决于目标静态文件的内容。

Doing this, the browser will never cache the static files declared in your index.html for example (because will always received a 302 Moved Temporarily ), but will only cache the ones with the hash version (the server will answer 200 for them). 这样做,浏览器永远不会缓存index.html声明的静态文件(因为它总是会收到302 Moved Temporarily ),但只会缓存带有哈希版本的那些(服务器将为它们回答200 )。 So the browser cache will be used efficiently for those static files with hash version. 因此,浏览器缓存将有效地用于具有哈希版本的静态文件。

Disclaimer: I'm the author of CorrectBrowserCacheHandlerFilter.java . 免责声明:我是CorrectBrowserCacheHandlerFilter.java的作者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM