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

发布于 2024-10-02 23:26:50 字数 512 浏览 1 评论 0原文

这就是我们防止浏览器缓存 JS 和 CSS 文件的方法。这看起来有点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> 

更新:我们想要防止缓存的原因是确保在发布新版本时加载较新版本的文件。

This is how we prevent caching of JS and CSS files by browsers. This seems slightly hacky.. is there a better way?

<%
//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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

断桥再见 2024-10-09 23:26:50

您希望 CSS 和 JS 被缓存。当他们回来时,它可以加快网页的加载速度。添加时间戳后,您的用户将被迫一次又一次地下载它。

如果您想确保它们始终具有新版本,请让您的构建系统在文件末尾添加构建号而不是时间戳。

如果您在开发中遇到问题,请确保将浏览器设置为不缓存文件,或将开发页面上的标头设置为不缓存。

You want CSS and JS to be cached. 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.

つ可否回来 2024-10-09 23:26:50

缓存是你的朋友。如果浏览器错误地缓存这些文件,则意味着您的 Web 服务器与 JS 和 CSS 文件本身(而不是使用它们的 HTML 页面)一起发送的 HTTP 标头有问题。浏览器使用这些标头来确定是否可以缓存该文件。

您的 Web 服务器可以发送这些标头(在它提供的每个 JS 和 CSS 文件上)来告诉浏览器不要缓存它们:

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

但这会增加您网站上的网络负载,用户会发现页面加载速度变慢。您可以更宽松一点,允许浏览器缓存 CSS 文件 60 秒:

Cache-Control: max-age=60

如果您确实希望浏览器在每次加载页面时检查新文件,您仍然可以保存一些使用 ETag 的网络流量:

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

ETag 只是您的 Web 服务器每次文件更改时组成的唯一标识符。下次浏览器需要该文件时,它会询问服务器“/js/pm.init.js 是否仍有 ETag o2389r98ur0w3894tuq894?”如果是这样,您的服务器只会说“是”。这样您的服务器就不必再次发送整个文件,用户也不必等待它加载。双赢。

如何说服您的 Web 服务器自动生成 ETag 取决于服务器。通常并不难。

我以前见过你使用的 hack。就像网络上的很多东西一样,它不是很漂亮,也不是特别高效,但它确实有效。

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). 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:

Cache-Control: no-store
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:

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:

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. The next time the browser wants the file, it asks the server, "does /js/pm.init.js still have the 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. 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.

埋情葬爱 2024-10-09 23:26:50

如果我们想要防止缓存的原因是为了确保在我们发布新版本时加载较新版本的文件。,您希望在有新版本时加载新的 js,而不是所有的时间。

为了做到这一点,您希望“ts”值与文件链接,而不是与一天中的时间链接。
您可以使用以下系统之一:

  1. ts = 文件的时间戳
  2. ts = 文件的 MD5(或任何校验和)
  3. ts = 代码的版本。如果您有一个执行部署的脚本,请确保它将版本代码(或发布日期)添加到某些将分配给 ts 的包含文件中。

这样,浏览器仅在文件是新的时才会重新加载该文件,而不是每次都重新加载。

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.

In order to do that you want that the "ts" value is linked with the file not with the time of the day.
You can either use one of these system:

  1. ts = Timestamp OF THE FILE
  2. ts = MD5 (or whatever checksum) of the FILE
  3. ts = version of the code. 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.

In this way the browser will reload the file only if it is new and not all the times.

无所谓啦 2024-10-09 23:26:50

一个简单的方法是使用 URL 中 js 或 css 文件的上次修改日期而不是时间戳。仅当服务器上有新版本的文件时,这才会起到阻止缓存的作用。

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. This would have the effect of preventing caching only when there is a new version of the file on the server.

灼疼热情 2024-10-09 23:26:50

编辑

如果您使用 Spring Boot,现在可以更简单地防止缓存已修改的文件。

您需要做的就是将其添加到 application.properties:

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

如果您使用 Thymeleaf 或 FreeMarker,它是完全自动配置的。如果您使用 JSP,则需要手动声明 ResourceUrlEncodingFilter。

在这里阅读更多内容:

现在下面是我的“旧”帖子,它也可以工作,但需要更多工作。


由于您使用的是 Java,因此您也有可能使用 Maven 来管理您的项目。

在这种情况下,为了提高性能,并确保在生成软件的新版本时没有浏览器缓存您的静态资源,您应该将所有样式表和 JavaScript 文件合并到其类型的单个文件中,并且您应该创建新版本时更改资源 URL。

幸运的是,maven 可以在构建时为您完成所有这些工作。您需要 minify-maven-pluginmaven-replacer-plugin

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
lt;/token>
                        <value>${timestamp}</value>
                    </replacement>
                </replacements>
            </configuration>
        </execution>
    </executions>
</plugin>

This is how to include your static resources in 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>

Edit

In case you are using Spring Boot it's now much simpler to prevent caching of modified files.

All you need to do is add this to 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. If you are using JSPs you need to manually declare a 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

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.

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.

Luckily maven can do all this for you at build-time. You'll need minify-maven-plugin and maven-replacer-plugin.

This excerpt of a pom.xml should get you started:

<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
lt;/token>
                        <value>${timestamp}</value>
                    </replacement>
                </replacements>
            </configuration>
        </execution>
    </executions>
</plugin>

This is how to include your static resources in 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>
檐上三寸雪 2024-10-09 23:26:50

出于调试目的,请安装 FireFox 的Web 开发人员工具栏并在那里激活“停用缓存”

更新:
安装 FireBug 后,您可以在网络选项卡设置中禁用缓存

For debug purposes, install the web developer toolbar for FireFox and activate there "deactivate Cache"

Update:
When you have FireBug installed, you can disable caching as well in the network tab settings.

百变从容 2024-10-09 23:26:50

如果您可以在应用程序中包含 Java Servlet Filter,这里有一个可行的解决方案: CorrectBrowserCacheHandlerFilter.java

基本上,当您的浏览器请求静态文件时,服务器会将每个请求重定向到同一个请求,但带有哈希查询参数(例如 ?v=azErT),该参数取决于静态文件的内容目标静态文件。

这样做,浏览器将永远不会缓存在 index.html 中声明的静态文件(因为总是会收到 302 Moved Temporarily),而只会缓存那些与哈希版本(服务器将为他们回答200)。因此,对于那些具有哈希版本的静态文件,浏览器缓存将得到有效利用。

免责声明:我是 CorrectBrowserCacheHandlerFilter.java 的作者。

If you can include Java Servlet Filter in your application, here is a working solution: 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.

Doing this, the browser will never cache the static files declared in your index.htmlfor 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). So the browser cache will be used efficiently for those static files with hash version.

Disclaimer: I'm the author of CorrectBrowserCacheHandlerFilter.java.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文