2010-11-17 17 views
20

Así es como evitamos el almacenamiento en caché de archivos JS y CSS por los navegadores. Esto parece un poco hacky ... ¿hay una mejor manera?Mejor manera de evitar el almacenamiento en caché del navegador de archivos JavaScript

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

Actualización: La razón por la que queremos prevenir el almacenamiento en caché es asegurar la versión más reciente de los archivos se cargan cuando hacemos un nuevo lanzamiento.

+3

¿Se deben obtener cada carga de página o solo cuando se realiza una nueva versión? –

+2

Sí ¿por qué en el mundo querría * evitar * el almacenamiento en caché de su contenido estático? Eso es exactamente lo contrario de lo que las personas generalmente hacen. – Pointy

+2

@Nick Craver & Pointy: ¿Tal vez está depurando y no quiere borrar el caché cada vez? Eso es todo lo que puedo entender. – Robusto

Respuesta

20

Desea CSS y JS en caché. Acelera la carga de la página web cuando vuelven. Al agregar una marca de tiempo, su usuario se verá obligado a descargarlo una y otra vez.

Si desea asegurarse de que siempre tengan una nueva versión, haga que su sistema de compilación agregue un número de compilación al final del archivo en lugar de una marca de tiempo.

Si tiene problemas solo con el desarrollador, asegúrese de configurar sus navegadores para que no almacenen en caché los archivos o establezca encabezados en sus páginas dev para que no se almacenen en caché.

+0

"Al agregar una marca de tiempo, su usuario se verá obligado a descargarla una y otra vez". (Esto tiene sentido). Pero luego dijiste: "Si quieres asegurarte de que siempre tengan una nueva versión, haz que tu sistema de compilación agregue un número de compilación al final del archivo en lugar de una marca de tiempo". (Esto parece contradecir su primera declaración). – AlvinfromDiaspar

+1

Me encanta cuando las preguntas de 8 años reciben comentarios. Bueno, uno actualiza cada vez, el otro solo lo actualiza cuando cambia. Lo ideal es que establezcas los encabezados de caché adecuados y no necesites hacerlo. – epascarello

17

Caching es tu amigo. Si los navegadores están guardando en caché estos archivos incorrectamente, significa que algo está mal con los encabezados HTTP que su servidor web está enviando junto con los archivos JS y CSS (no la página HTML que los usa). El navegador usa esos encabezados para determinar si puede almacenar en caché el archivo.

Su servidor web puede enviar estas cabeceras (en todos los archivos JS y CSS sirve) para indicar a los navegadores que no hagan caché ellos:

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

Pero eso va a aumentar la carga de la red en su sitio, y los usuarios ver la carga de la página más lenta. Usted podría ser un poco más flexible y permitir que el navegador para almacenar en caché el archivo CSS durante 60 segundos:

Cache-Control: max-age=60 

Si realmente desea que el navegador para comprobar si hay un nuevo archivo con cada carga de página única, puede todavía ahorrar algo de tráfico de red mediante el uso de un ETag:

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

El ETag es simplemente un identificador único servidor web constituye cada vez que los cambios en los archivos. La próxima vez que el navegador quiere el archivo, le pregunta al servidor, "¿/js/pm.init.js todavía tiene ETag o2389r98ur0w3894tuq894?" y si es así, su servidor simplemente dice "sí". De esta forma, su servidor no tiene que enviar todo el archivo nuevamente, y el usuario no tiene que esperar a que se cargue. Ganar-ganar

Cómo convencer a su servidor web de que genere automáticamente ETags depende del servidor. Por lo general, no es difícil.

He visto el truco que está utilizando antes. Al igual que en la Web, no es bonito ni particularmente eficiente, pero funciona.

1

Para fines de depuración, instalar el web developer toolbar para FireFox y active allí "desactivar Caché"

Actualización:
Cuando haya instalado FireBug, puede disable caching as well in the network tab settings.

+1

¿Tenemos un tipo similar de herramienta para Chrome? – Raghav

+1

Google Chrome incluye las herramientas para desarrolladores de Chrome integradas en el navegador. si abre las herramientas de desarrollo de Chrome, verá el engranaje en la esquina inferior derecha. Haga clic en eso y marque la casilla "Desactivar caché" debajo del encabezado "General". – Matt

11

If El motivo por el que queremos evitar el almacenamiento en caché es garantizar que la versión más nueva de los archivos se cargue cuando hacemos una nueva versión., desea que la nueva js se cargue cuando HAY una NUEVA versión, no todas las veces.

Para hacer eso, quiere que el valor "ts" esté vinculado con el archivo, no con la hora del día. Puede utilizar uno de estos sistemas:

  1. ts = marca del archivo
  2. ts = MD5 (o lo que sea la suma de comprobación) del archivo
  3. ts = versión del código. Si tiene una secuencia de comandos que realiza la implementación, asegúrese de que agrega el código de la versión (o la fecha de la versión) en algún archivo de inclusión que se asignará a ts.

De esta manera, el navegador volverá a cargar el archivo solo si es nuevo y no todas las veces.

3

Un enfoque simple para esto sería usar la última fecha de modificación de los archivos js o css en la URL en lugar de una marca de tiempo. Esto tendría el efecto de evitar el almacenamiento en caché solo cuando haya una nueva versión del archivo en el servidor.

3

Editar

En caso de que utilice la primavera de arranque ahora es mucho más simple para evitar el almacenamiento en caché de archivos modificados.

Todo lo que necesita hacer es añadir esto a application.properties:

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

Si está utilizando thymeleaf o FreeMarker que esté completamente configura automáticamente. Si está utilizando JSPs necesita declarar manualmente un ResourceUrlEncodingFilter.

Leer más aquí: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content

Lo que sigue ahora es mi "viejo" post que también funciona, pero requiere más trabajo.


Dado que está utilizando Java existe la posibilidad de que también esté utilizando maven para gestionar su proyecto. En ese caso, para mejorar el rendimiento y asegurarse de que ningún navegador almacena en caché sus recursos estáticos cuando se produce una nueva versión de su software, debe combinar todas sus hojas de estilo y archivos de JavaScript en un solo archivo de su tipo , y debe hacer que sus URL de recursos cambien cuando crea una nueva versión.

Afortunadamente, maven puede hacer todo esto por ti en tiempo de compilación. Necesitará minify-maven-plugin y maven-replacer-plugin.

Este extracto de un pom.xml debería empezar:

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

Ésta es la forma de incluir sus recursos estáticos en la cabecera.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> 
0

Si puede incluir Java Servlet de filtro en su aplicación, aquí es una solución de trabajo: CorrectBrowserCacheHandlerFilter.java

Básicamente, cuando el navegador solicita los archivos estáticos, el servidor volverá a dirigir cada solicitudes a la misma pero con un parámetro de consulta hash (?v=azErT por ejemplo) que depende del contenido del archivo estático de destino.

Al hacer esto, el navegador nunca va a almacenar en caché los archivos estáticos declarados en su index.html por ejemplo (porque siempre será recibido una 302 Moved Temporarily), pero sólo en caché los que tienen la versión de hash (el servidor responderá 200 para ellos). Por lo tanto, la memoria caché del navegador se utilizará de manera eficiente para los archivos estáticos con la versión hash.

Descargo de responsabilidad: soy el autor de CorrectBrowserCacheHandlerFilter.java.

Cuestiones relacionadas