He notado que algunos navegadores (en particular, Firefox y Opera) son muy entusiastas al usar copias en caché de archivos .css y .js , incluso entre sesiones de navegador. Esto genera un problema cuando actualiza uno de estos archivos, pero el navegador del usuario sigue utilizando la copia en caché.
La pregunta es: ¿cuál es la forma más elegante de obligar al navegador del usuario a volver a cargar el archivo cuando ha cambiado?
Idealmente, la solución no obligaría al navegador a recargar el archivo en cada visita a la página. Publicaré mi propia solución como respuesta, pero tengo curiosidad por saber si alguien tiene una mejor solución y dejaré que sus votos decidan.
Actualización:
Después de permitir una discusión aquí por un tiempo, he encontrado que la sugerencia de John Millikin y da5id es útil. Resulta que hay un término para esto: auto-versionado .
He publicado una nueva respuesta a continuación, que es una combinación de mi solución original y la sugerencia de John.
Otra idea sugerida por SCdF sería agregar una cadena de consulta falsa al archivo. (Algún código de Python para usar automáticamente la marca de tiempo como una cadena de consulta falsa fue enviada por pi ). Sin embargo, se debate si el navegador guardará o no en caché un archivo con una cadena de consulta. (Recuerde, queremos que el navegador guarde en caché el archivo y lo use en futuras visitas. Solo queremos que recupere el archivo nuevamente cuando haya cambiado).
Como no está claro qué sucede con una cadena de consulta falsa, no acepto esa respuesta.
ExpiresActive On ExpiresDefault "modification"
.iframe.contentWindow.location.reload(true)
. Consulte el método (4) de stackoverflow.com/a/22429796/999120 : se trata de imágenes, pero se aplica lo mismo.Respuestas:
Actualización: reescrita para incorporar sugerencias de John Millikin y da5id . Esta solución está escrita en PHP, pero debe adaptarse fácilmente a otros idiomas.
Actualización 2: Incorporación de comentarios de Nick Johnson de que la
.htaccess
expresión regular original puede causar problemas con archivos comojson-1.3.js
. La solución es reescribir solo si hay exactamente 10 dígitos al final. (Debido a que 10 dígitos cubren todas las marcas de tiempo del 9/9/2001 al 20/11/2286).Primero, usamos la siguiente regla de reescritura en .htaccess:
Ahora, escribimos la siguiente función PHP:
Ahora, donde sea que incluya su CSS, cámbielo de esto:
A esto:
De esta manera, nunca más tendrá que modificar la etiqueta de enlace, y el usuario siempre verá el último CSS. El navegador podrá almacenar en caché el archivo CSS, pero cuando realice cambios en su CSS, el navegador verá esto como una nueva URL, por lo que no utilizará la copia en caché.
Esto también puede funcionar con imágenes, favicons y JavaScript. Básicamente todo lo que no se genera dinámicamente.
fuente
file_exists
realmente necesario el primer cheque?filemtime
devolverá falso en caso de falla, entonces, ¿por qué no simplemente asignar el valor de tiempo de archivo a una variable y verificar si es falso antes de cambiar el nombre del archivo? Eso reduciría una operación de archivo innecesaria que realmente sumaría.Técnica simple del lado del cliente
En general, el almacenamiento en caché es bueno. Por lo tanto, hay un par de técnicas, dependiendo de si está solucionando el problema mientras desarrolla un sitio web, o si está tratando de controlar el almacenamiento en caché en un entorno de producción.
Los visitantes generales de su sitio web no tendrán la misma experiencia que tienen cuando desarrollan el sitio. Dado que el visitante promedio visita el sitio con menos frecuencia (tal vez solo unas pocas veces al mes, a menos que sea una red de Google o hi5), es menos probable que tenga sus archivos en caché, y eso puede ser suficiente. Si desea forzar una nueva versión en el navegador, siempre puede agregar una cadena de consulta a la solicitud y aumentar el número de versión cuando realice cambios importantes:
Esto asegurará que todos obtengan el nuevo archivo. Funciona porque el navegador mira la URL del archivo para determinar si tiene una copia en caché. Si su servidor no está configurado para hacer nada con la cadena de consulta, se ignorará, pero el nombre se verá como un nuevo archivo para el navegador.
Por otro lado, si está desarrollando un sitio web, no desea cambiar el número de versión cada vez que guarda un cambio en su versión de desarrollo. Eso sería tedioso.
Entonces, mientras desarrolla su sitio, un buen truco sería generar automáticamente un parámetro de cadena de consulta:
Agregar una cadena de consulta a la solicitud es una buena manera de versionar un recurso, pero para un sitio web simple esto puede ser innecesario. Y recuerde, el almacenamiento en caché es algo bueno.
También vale la pena señalar que el navegador no es necesariamente tacaño para mantener los archivos en caché. Los navegadores tienen políticas para este tipo de cosas, y generalmente se rigen por las reglas establecidas en la especificación HTTP. Cuando un navegador realiza una solicitud a un servidor, parte de la respuesta es un encabezado CADUCADO ... una fecha que le indica al navegador cuánto tiempo debe mantenerse en caché. La próxima vez que el navegador encuentre una solicitud para el mismo archivo, verá que tiene una copia en la memoria caché y buscará la fecha de CADUCIDAD para decidir si debe usarse.
Entonces, lo creas o no, en realidad es tu servidor el que está haciendo que el caché del navegador sea tan persistente. Puede ajustar la configuración de su servidor y cambiar los encabezados de CADUCES, pero la pequeña técnica que he escrito anteriormente es probablemente una forma mucho más sencilla de hacerlo. Dado que el almacenamiento en caché es bueno, generalmente desea establecer esa fecha en el futuro (un "Encabezado de caducidad de futuro lejano") y utilizar la técnica descrita anteriormente para forzar un cambio.
Si está interesado en obtener más información sobre HTTP o cómo se realizan estas solicitudes, un buen libro es "Sitios web de alto rendimiento" de Steve Souders. Es una muy buena introducción al tema.
fuente
<link href='myCss.css?dev=14141'...>
El complemento mod_pagespeed de Google para apache hará el auto versionado por usted. Es muy hábil.
Analiza HTML al salir del servidor web (funciona con PHP, rails, python, HTML estático, cualquier cosa) y reescribe enlaces a CSS, JS, archivos de imagen para que incluyan un código de identificación. Sirve los archivos en las URL modificadas con un control de caché muy largo en ellos. Cuando los archivos cambian, cambia automáticamente las URL para que el navegador tenga que volver a buscarlas. Básicamente funciona, sin ningún cambio en su código. Incluso minificará tu código al salir también.
fuente
En lugar de cambiar la versión manualmente, le recomendaría que use un hash MD5 del archivo CSS real.
Entonces su URL sería algo así como
Todavía podría usar la regla de reescritura para eliminar el hash, pero la ventaja es que ahora puede configurar su política de caché en "caché para siempre", ya que si la URL es la misma, eso significa que el archivo no ha cambiado.
Luego puede escribir un script de shell simple que calcule el hash del archivo y actualice su etiqueta (probablemente desee moverlo a un archivo separado para su inclusión).
Simplemente ejecute ese script cada vez que CSS cambie y estará bien. El navegador SOLO volverá a cargar sus archivos cuando se modifiquen. Si realiza una edición y luego la deshace, no hay problema en averiguar a qué versión debe regresar para que sus visitantes no vuelvan a descargar.
fuente
No estoy seguro de por qué ustedes están tomando tanto dolor para implementar esta solución.
Todo lo que debe hacer si obtiene la marca de tiempo modificada del archivo y la agrega como una cadena de consulta al archivo
En PHP lo haría como:
filemtime es una función PHP que devuelve la marca de tiempo modificada del archivo.
fuente
mycss.css?1234567890
.<link rel="stylesheet" href="mycss.css?<?php echo filemtime('mycss.css') ?>"/>
, en caso de que algunos de los argumentos en este hilo sobre el almacenamiento en caché de URL con variables GET (en el formato sugerido) sean correctos?ver=
quién sabe!Simplemente puede colocar
?foo=1234
al final de su importación css / js, cambiando 1234 para que sea lo que quiera. Eche un vistazo a la fuente SO html para ver un ejemplo.La idea es que el? los parámetros se descartan / ignoran en la solicitud de todos modos y puede cambiar ese número cuando implementa una nueva versión.
Nota: Hay algún argumento con respecto a cómo esto afecta exactamente el almacenamiento en caché. Creo que la esencia general de esto es que las solicitudes GET, con o sin parámetros, deben ser almacenables en caché, por lo que la solución anterior debería funcionar.
Sin embargo, depende tanto del servidor web decidir si quiere adherirse a esa parte de la especificación como al navegador que usa el usuario, ya que de todos modos puede seguir adelante y pedir una versión nueva de todos modos.
fuente
He escuchado esto llamado "auto versionado". El método más común es incluir el tiempo estático del archivo estático en algún lugar de la URL y eliminarlo utilizando controladores de reescritura o confs de URL:
Ver también:
fuente
Las aproximadamente 30 respuestas existentes son excelentes consejos para un sitio web de alrededor de 2008. Sin embargo, cuando se trata de una aplicación moderna de una sola página (SPA), podría ser el momento de repensar algunos supuestos fundamentales ... específicamente la idea de que es deseable que el servidor web sirva solo la versión más reciente y única de un archivo.
Imagine que es un usuario que tiene la versión M de un SPA cargada en su navegador:
/some.template
/some.template
: ¿desea que devuelva la versión M o N de la plantilla?Si el formato
/some.template
cambió entre las versiones M y N (o se cambió el nombre del archivo o lo que sea) , probablemente no desee que se envíe la versión N de la plantilla al navegador que ejecuta la versión anterior M del analizador . †Las aplicaciones web se encuentran con este problema cuando se cumplen dos condiciones:
Una vez que su aplicación necesita servir varias versiones en paralelo, resolver el almacenamiento en caché y la "recarga" se vuelve trivial:
/v<release_tag_1>/…files…
,/v<release_tag_2>/…files…
<script>
y<link>
etiquetas, etc. para apuntar a ese archivo en uno de los directorios versionadosEse último paso parece complicado, ya que podría requerir llamar a un creador de URL para cada URL en su código del lado del servidor o del lado del cliente. O simplemente puede hacer un uso inteligente de la
<base>
etiqueta y cambiar la versión actual en un solo lugar.† Una forma de evitar esto es ser agresivo al obligar al navegador a recargar todo cuando se lanza una nueva versión. Pero en aras de permitir que se completen las operaciones en progreso, aún puede ser más fácil admitir al menos dos versiones en paralelo: v-current y v-previous.
fuente
base
etiqueta! En cuanto a admitir código antiguo: esto no siempre es una posibilidad, ni tampoco es una buena idea. Las nuevas versiones de código pueden admitir cambios de última hora en otras partes de una aplicación o pueden implicar soluciones de emergencia, parches de vulnerabilidad, etc. Todavía tengo que implementar esta estrategia yo mismo, pero siempre he pensado que la arquitectura general debería permitir que las implementaciones etiqueten una versión anterior comoobsolete
y forzar una recarga la próxima vez que se realice una llamada asincrónica (o simplemente desautorizar forzosamente todas las sesiones a través de WebSockets )¡No use foo.css? Version = 1! Se supone que los navegadores no almacenan en caché las URL con variables GET. Según http://www.thinkvitamin.com/features/webapps/serving-javascript-fast , aunque IE y Firefox ignoran esto, ¡Opera y Safari no lo hacen! En su lugar, use foo.v1234.css y use las reglas de reescritura para eliminar el número de versión.
fuente
En Laravel (PHP) podemos hacerlo de la siguiente manera clara y elegante (usando la marca de tiempo de modificación de archivo):
Y similar para CSS
Ejemplo de salida html (
filemtime
tiempo de retorno como una marca de tiempo Unix )fuente
RewriteRule necesita una pequeña actualización para los archivos js o css que contienen una versión de notación de puntos al final. Por ejemplo, json-1.3.js.
Agregué una clase de negación de puntos [^.] A la expresión regular, así que .number. es ignorado
fuente
^(.*)\.[\d]{10}\.(css|js)$ $1.$2
[^.]
aquí. Además, no hay ningún beneficio en escribir\d
dentro de una clase de caracteres:\d+
hará lo mismo. Según lo publicado, su patrón coincidirá con cualquier número de caracteres (con avidez), luego un punto literal, luego un no-punto, luego uno o más dígitos, luego un punto, luegocss
ojs
, luego el final del nombre de archivo. No hay coincidencia para su entrada de muestra: regex101.com/r/RPGC62/1Para ASP.NET 4.5 y superior, puede usar la agrupación de scripts .
El paquete incluye otros beneficios, incluido un mayor rendimiento en la primera carga de páginas con minificación.
fuente
Aquí hay una solución de JavaScript puro
Lo anterior buscará la última vez que el usuario visitó su sitio. Si la última visita fue antes de lanzar un nuevo código, se usa
location.reload(true)
para forzar la actualización de la página del servidor.Por lo general, tengo esto como el primer script dentro del,
<head>
así que se evalúa antes de que se cargue cualquier otro contenido. Si se necesita una recarga, el usuario apenas lo nota.Estoy usando el almacenamiento local para almacenar la marca de tiempo de la última visita en el navegador, pero puede agregar cookies a la mezcla si desea admitir versiones anteriores de IE.
fuente
Publicación interesante Después de leer todas las respuestas aquí combinadas con el hecho de que nunca he tenido ningún problema con las cadenas de consulta "falsas" (que no estoy seguro de por qué todos son tan reacios a usar esto), creo que la solución (que elimina la necesidad de reglas de reescritura de Apache) como en la respuesta aceptada) es calcular un HASH corto del contenido del archivo CSS (en lugar de la fecha y hora del archivo) como una cadena de consulta falsa.
Esto resultaría en lo siguiente:
Por supuesto, las soluciones de fecha y hora también hacen el trabajo en el caso de editar un archivo CSS, pero creo que se trata del contenido del archivo CSS y no de la fecha y hora del archivo, entonces, ¿por qué mezclarlos?
fuente
Para mi desarrollo, encuentro que Chrome tiene una gran solución.
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
Con las herramientas de desarrollador abiertas, simplemente haga clic en el botón Actualizar y suéltelo una vez que pase el cursor sobre "Vaciar caché y recarga dura".
¡Este es mi mejor amigo, y es una forma súper liviana de obtener lo que quieres!
fuente
¡Gracias a Kip por su solución perfecta!
Lo extendí para usarlo como Zend_view_Helper. Debido a que mi cliente ejecuta su página en un host virtual, también la extendí para eso.
Espero que ayude a alguien más también.
Saludos y gracias.
fuente
No he encontrado el enfoque DOM del lado del cliente que crea el elemento de nodo de script (o CSS) dinámicamente:
fuente
Google Chrome tiene la opción Hard Reload , así como la opción Vaciar caché y Hard Reload . Puede hacer clic y mantener presionado el botón de recarga (en modo Inspeccionar) para seleccionar uno.
fuente
ant menu
>More Tools
>Developer Tools
, aliasright click
>Inspect Element
. También hay una configuración enterrada en algún lugar de las herramientas de desarrollo (se me olvida la ubicación) para recargar con fuerza en cada recarga.Puede forzar un "almacenamiento en caché de toda la sesión" si agrega el ID de sesión como un parámetro espurio del archivo js / css:
Si desea un almacenamiento en caché de toda la versión, puede agregar un código para imprimir la fecha del archivo o similar. Si está utilizando Java, puede usar una etiqueta personalizada para generar el enlace de una manera elegante.
fuente
Digamos que tiene un archivo disponible en:
puede agregar un parámetro de consulta con información de versión en el URI, por ejemplo:
o puede anteponer información de versión, por ejemplo:
En mi humilde opinión, el segundo método es mejor para archivos CSS porque pueden referirse a imágenes usando URL relativas, lo que significa que si especifica un me
background-image
gusta así:su URL será efectivamente:
Esto significa que si actualiza el número de versión utilizado, el servidor lo tratará como un nuevo recurso y no utilizará una versión en caché. Si basa su número de versión en Subversion / CVS / etc. revisión esto significa que se notarán cambios en las imágenes a las que se hace referencia en los archivos CSS. Eso no está garantizado con el primer esquema, es decir, la URL
images/happy.gif
relativa/styles/screen.css?v=1235
es la/styles/images/happy.gif
que no contiene ninguna información de versión.He implementado una solución de almacenamiento en caché utilizando esta técnica con servlets de Java y simplemente manejo las solicitudes
/v/*
con un servlet que delega en el recurso subyacente (es decir/styles/screen.css
). En el modo de desarrollo que el almacenamiento en caché conjunto cabeceras que le dicen al cliente que compruebe siempre la frescura de los recursos con el servidor (esto típicamente resulta en un 304 si delega a Tomcat deDefaultServlet
y.css
,.js
, etc archivo no ha cambiado), mientras que en el modo de implementación Configuré encabezados que dicen "caché para siempre".fuente
<?php header( 'Location: folder1/login.phtml' ); ?>
.Simplemente puede agregar un número aleatorio con la URL de CSS / JS como
fuente
Para ASP.NET, supongo que la próxima solución con opciones avanzadas (modo de depuración / liberación, versiones):
Archivos Js o Css incluidos de esta manera:
Global.JsPostfix y Global.CssPostfix se calcula de la siguiente manera en Global.asax:
fuente
Recientemente resolví esto usando Python. Aquí el código (debería ser fácil de adoptar en otros idiomas):
Este código básicamente agrega la marca de tiempo de los archivos como un parámetro de consulta a la URL. La llamada de la siguiente función
resultará en
La ventaja, por supuesto, es que nunca más tendrá que cambiar su html, tocar el archivo CSS activará automáticamente una invalidación de caché. Funciona muy bien y los gastos generales no se notan.
fuente
Si está utilizando git + PHP, puede volver a cargar el script desde la memoria caché cada vez que haya un cambio en el repositorio de git, utilizando el siguiente código:
fuente
Si usted es un desarrollador que busca evitar el almacenamiento en caché, la pestaña de red de Chrome tiene la opción de deshabilitar la memoria caché. De lo contrario, puede hacerlo sin un marco de representación del servidor utilizando dos etiquetas de script.
fuente
Esta pregunta es muy antigua y aparece a primera vista cuando alguien busca en Google este problema. Esta no es una respuesta a la pregunta de la forma en que op lo quiere, sino una respuesta a los desarrolladores con este problema durante el desarrollo y las pruebas. Y no puedo publicar una nueva pregunta sobre este tema, ya que se marcará como duplicado.
Como muchos otros, solo quería eliminar el almacenamiento en caché brevemente.
"keep caching consistent with the file"
... es demasiado complicado ...En términos generales, no me importa cargar más, incluso cargar de nuevo archivos que no cambiaron, en la mayoría de los proyectos, es prácticamente irrelevante. Mientras desarrollamos una aplicación, en su mayoría estamos cargando desde el disco, en adelante, por
localhost:port
lo que esteincrease in network traffic
problema no es un problema decisivo .La mayoría de los proyectos pequeños solo están jugando, nunca terminan en producción. así que para ellos no necesitas nada más ...
Como tal, si usa Chrome Dev Tools , puede seguir este enfoque de desactivación del almacenamiento en caché como en la imagen a continuación:
Y si tiene problemas de almacenamiento en caché de Firefox :
Haga esto solo en el desarrollo, también necesita un mecanismo para forzar la recarga para la producción, ya que sus usuarios usarán módulos antiguos invalidados de caché si actualiza su aplicación con frecuencia y no proporciona un mecanismo de sincronización de caché dedicado como los descritos en las respuestas encima.
Sí, esta información ya está en respuestas anteriores, pero aún necesitaba hacer una búsqueda en Google para encontrarla.
Esperemos que esta respuesta sea muy clara y ahora no sea necesario.
fuente
Parece que todas las respuestas aquí sugieren algún tipo de versión en el esquema de nombres, que tiene sus desventajas.
Los navegadores deben saber qué almacenar en caché y qué no almacenar en caché al leer la respuesta de los servidores web, en particular los encabezados http, ¿por cuánto tiempo es válido este recurso? ¿Se actualizó este recurso desde la última vez que lo recuperé? etcétera
Si las cosas están configuradas 'correctamente', solo actualizar los archivos de su aplicación debería (en algún momento) actualizar las memorias caché de los navegadores. Por ejemplo, puede configurar su servidor web para que le diga al navegador que nunca guarde en caché los archivos (lo cual es una mala idea).
Una explicación más detallada de cómo funciona eso está aquí https://www.mnot.net/cache_docs/#WORK
fuente
Simplemente agregue este código, donde desea realizar una recarga dura (obligar al navegador a volver a cargar archivos CSS / JS en caché). Haga esto dentro de .load para que no se actualice como un bucle
fuente
Simplemente use el código del lado del servidor para agregar la fecha del archivo ... de esa manera se almacenará en caché y solo se volverá a cargar cuando el archivo cambie
En ASP.NET
Esto se puede simplificar para:
Al agregar un método de extensión a su proyecto para extender la página:
fuente
Sugiero implementar el siguiente proceso:
versione sus archivos css / js cada vez que implemente, algo como: screen.1233.css (el número puede ser su revisión SVN si usa un sistema de versiones)
minimízalos para optimizar los tiempos de carga
fuente