Лучший способ предотвратить кеширование браузером файлов JavaScript

Так мы предотвращаем кеширование файлов JS и CSS браузерами. Это кажется немного взломанным.. есть ли лучший способ?

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

Обновление. Причина, по которой мы хотим предотвратить кеширование, - обеспечить загрузку более новой версии файлов при создании новой версии.

Ответ 1

Вы хотите, чтобы CSS и JS были кэшированы. Это ускоряет загрузку веб-страницы, когда они возвращаются. Добавьте временную метку, ваш пользователь будет вынужден снова и снова загружать ее.

Если вы хотите убедиться, что у них всегда есть новая версия, чем ваша система сборки добавит номер сборки в конец файла, а не временную метку.

Если у вас есть проблемы с ним только в dev, убедитесь, что ваши браузеры не кэшируют файлы или не устанавливают заголовки на своих страницах dev, чтобы не кэшировать.

Ответ 2

Кэширование - ваш друг. Если браузеры кэшируют эти файлы неправильно, это означает, что что-то не так с заголовками HTTP, которые ваш веб-сервер отправляет вместе с самими файлами JS и CSS (а не с HTML-страницей, которая их использует). Браузер использует эти заголовки, чтобы выяснить, может ли он кэшировать файл.

Ваш веб-сервер может отправлять эти заголовки (на каждый файл JS и CSS, который он обслуживает), чтобы сообщить браузерам, что они не кэшируют их:

Cache-Control: no-cache
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 - это просто уникальный идентификатор, который ваш веб-сервер делает каждый раз при изменении файла. В следующий раз, когда браузеру понадобится файл, он спрашивает сервер: "У/js/pm.init.js все еще есть ETag o2389r98ur0w3894tuq894?" и если да, то ваш сервер просто говорит "да". Таким образом, вашему серверу больше не придется отправлять весь файл, и пользователю не нужно ждать его загрузки. Беспроигрышный.

Как убедить ваш веб-сервер в автогенерации ETags зависит от сервера. Обычно это не сложно.

Я видел взлом, который вы используете раньше. Как и в Интернете, это не очень или особенно эффективно, но оно работает.

Ответ 3

Если причина, по которой мы хотим предотвратить кеширование, заключается в том, чтобы загрузить новую версию файлов, когда мы создаем новую версию., вы хотите, чтобы новый js загружался, когда новый релиз НЕ был, не все время.

Чтобы сделать это, вы хотите, чтобы значение "ts" было связано с файлом не со временем дня. Вы можете использовать одну из этих систем:

  • ts = отметка времени файла
  • ts = MD5 (или любая контрольная сумма) FILE
  • ts = версия кода. Если у вас есть script, который делает развертывание, убедитесь, что он добавляет код версии (или дату выпуска) в некоторый файл include, который будет назначен для ts.

Таким образом, браузер перезагрузит файл только в том случае, если он новый и не все время.

Ответ 4

Простым подходом к этому было бы использовать последнюю измененную дату js или css файлов в URL вместо метки времени. Это могло бы предотвратить кеширование только тогда, когда на сервере появилась новая версия файла.

Ответ 5

Edit

Если вы используете Spring Boot, теперь гораздо проще предотвратить кэширование измененных файлов.

Все, что вам нужно сделать, это добавить это в application.properties:

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

Если вы используете Thymeleaf или FreeMarker, он полностью автоконфигурируется. Если вы используете JSP, вам нужно вручную объявить ResourceUrlEncodingFilter.

Подробнее здесь: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content

Далее следует мой "старый" пост, который также работает, но требует больше работы.


Поскольку вы используете Java, есть шанс, что вы также используете maven для управления вашим проектом.

В этом случае для повышения производительности и обеспечения того, чтобы ни один браузер не кэшировал ваши статические ресурсы при создании новой версии вашего программного обеспечения, вы должны объединить все свои таблицы стилей и файлы JavaScript в один файл своего типа, и вы должны изменить свои URL-адреса ресурсов при создании новой версии.

К счастью, maven может сделать все это для вас во время сборки. Вам понадобятся minify-maven-plugin и maven-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$</token>
                        <value>${timestamp}</value>
                    </replacement>
                </replacements>
            </configuration>
        </execution>
    </executions>
</plugin>

Вот как включить ваши статические ресурсы в 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>

Ответ 7

Если вы можете включить Java Servlet Filter в ваше приложение, вот работающее решение: CorrectBrowserCacheHandlerFilter.java

В основном, когда ваш браузер запрашивает статические файлы, сервер перенаправляет все запросы на один и тот же, но с параметром хэш-запроса (например, ?v=azErT), который зависит от содержимого целевого статического файла.

Выполняя это, браузер никогда не будет кэшировать статические файлы, объявленные в вашем index.html например (потому что всегда будет получать 302 Moved Temporarily), но будет кэшировать только те, у которых есть хеш-версия (сервер ответит 200 для них). Таким образом, кеш браузера будет эффективно использоваться для этих статических файлов с хэш-версией.

Отказ от ответственности: я являюсь автором CorrectBrowserCacheHandlerFilter.java.