Los conceptos básicos del almacenamiento en caché de clientes en palabras claras y ejemplos. Última modificación, Etag, Expires, Cache-control: max-age y otros encabezados

Mucha gente piensa que, de forma predeterminada, los archivos CSS conectados a través de un enlace o @import no se almacenan en caché. Tengo que decepcionarte. Es precisamente el css el que se almacena en caché en un archivo aparte, y es muy bueno, yo diría excelente. Esta información se verifica de manera confiable tanto en 6 como en adelante y en otros navegadores. Vale la pena señalar que muchos queridos caché de tales archivos a una velocidad completamente salvaje, por así decirlo, obtienen el primer lugar para este caso. Por cierto, es a este mismo mecanismo que Opera tiene en muchos casos una velocidad significativa en comparación con otros navegadores. Pero haré una reserva de inmediato de que este "super" almacenamiento en caché en Opera es una broma cruel cuando se usa la tecnología AJAX. Mientras que otros modifican los racimos de pollitos cuando usan AJAX, Opera toma el anterior. Pero esta es una canción de un tema aparte.

Almacenamiento en caché de CSS

¡PERO! Todavía existen algunos problemas de duelo en esta dirección. Esto se debe, por regla general, a un servidor Apache configurado incorrectamente, que produce encabezados incorrectos. Y con la ayuda del encabezado, puede controlar el almacenamiento en caché de los archivos. Por defecto, por supuesto, el caché siempre está habilitado. Pero hay ocasiones en las que no es necesario almacenar archivos en caché. Para esto, los profesionales comienzan a bailar con panderetas sobre los encabezados HTTP. Pero si está leyendo este artículo completo, todavía está muy lejos de administrar los encabezados HTTP. Les aseguro que en un futuro próximo no se enfrentarán a tal tarea. Y, sin embargo, si sientes curiosidad hasta la médula, te contaré brevemente cómo sucede esto.

  1. envía el encabezado HTTP al servidor WEB; dicen, hola, pimiento dulce, dame el archivo CSS, de lo contrario, tengo CSS, pero la última vez hubo un cambio de este tipo.
  2. Y el servidor le dice en respuesta, muy dulce, no ha habido cambios desde ese momento, toma y usa tu viejo CSS con valentía.
  3. Si el CSS ha cambiado, entonces el navegador actualiza estúpidamente el CSS en su caché.

Bueno, ahora, si no cansado, entonces un poco de basura científica de algún tipo de experimento.

Te diré de inmediato que los principiantes en la WEB entenderán mal el texto inferior. Básicamente, esto será útil para aquellos que todavía se enfrentan a las tareas de deshabilitar y habilitar el caché.

Todos los experimentos se llevaron a cabo de forma real y pagada. Un buen hoster, por así decirlo, que le permite cambiar la estructura de los encabezados HTTP sin tener que paranoiarse de que serán pirateados por el encabezado HTTP :)

Modos de navegador

Entonces cualquier navegador tiene 2 modos:

1. Modo por defecto, el título devuelto es:

Control de caché: sin almacenamiento, sin caché, debe revalidar, verificación posterior = 0, verificación previa = 0

2. Modo de almacenamiento en caché habilitado, el título devuelto es:

Control de caché: privado, edad máxima = 10800, verificación previa = 10800

A continuación, describo el comportamiento de los navegadores.

FireFox 3.5 y superior

En el primero El modo almacena firmemente en caché los archivos JavaScript externos y ni siquiera busca actualizaciones, a menos que fuerce la actualización de la página. El CSS se valida mediante una solicitud de encabezado.

If-Modified-Since: "fecha actual" GMT If-None-Match: "código hash propio"

Es decir, el CSS solo se vuelve a cargar si realmente se ha actualizado.

en segundo lugar el modo deja de actualizar la página por completo. Es decir, incluso si hayamos cambiado el contenido que se muestra en la página en la base de datos, no muestra esto, incluso si se fuerza a actualizar, ya que envía una solicitud:

GET / HTTP / 1.1 Host: xxx.com Si-Modificado-Desde: fecha GMT actual

y obtiene la respuesta:

HTTP / 1.1 304 no modificado

Internet Explorer 8 (IE8)

En el primero El modo Internet Explorer envía solicitudes If-Modified-Since y If-None-Match para JavaScript y css, es decir, carga JavaScript y CSS solo si están realmente actualizados. Lo mismo ocurre si la página se ve obligada a actualizarse.

en segundo lugar El modo Internet Explorer también envía solicitudes If-Modified-Since y If-None-Match para JavaScript y css. Pero al mismo tiempo, ni siquiera intenta cargar / actualizar la página en sí, es decir, ni siquiera envía una solicitud, es decir, se actualizará tu js / css, pero no la plantilla y el contenido de la página. Incluso una actualización de página forzada no ayuda a actualizar el contenido.

Opera 10 y mayores

En el primero Modo Opera, en el primer modo, la actualización de js y CSS depende del valor de la opción Verificar imágenes en la configuración. Si la opción está configurada en Siempre, entonces la ópera envía solicitudes con If-Modified-Since & If-None-Match para buscar actualizaciones de js y css. Si se establece un valor, por ejemplo, 5 horas, entonces, en consecuencia, se comprobará una vez cada 5 horas o mediante una actualización de página forzada.

en segundo lugar modo, Opera no busca actualizaciones de js y CSS (no realiza solicitudes GET), y tampoco realiza una solicitud GET para la página en sí, es decir, no veremos actualizaciones de js y css ni actualizaciones de contenido, como en otras cosas y en otros navegadores. Pero con una actualización forzada, Opera es mejor. A diferencia de IE y FF, Opera solicita explícitamente el contenido de la página sin If-Modified-Since & If-None-Match. Las solicitudes de actualización de Js y CSS para la actualización forzada vienen con If-Modified-Since & If-None-Match.

conclusiones

  1. El almacenamiento en caché, si no comprende exactamente cómo funciona en diferentes navegadores y cuáles son las consecuencias, es algo bastante peligroso.
  2. El almacenamiento en caché se puede habilitar solo si la página se actualiza con poca frecuencia (es decir, si el sitio no tiene páginas que se actualizan en tiempo real) e incluso en este caso, es imperativo establecer un límite en el período de limitación de almacenamiento en caché (por ejemplo , unas horas o un día)
  3. FireFox se comporta, en mi opinión, un poco más inteligente que IE, porque incluso con el almacenamiento en caché deshabilitado, no busca constantemente actualizaciones de JavaScript, lo que parece lógico, porque JavaScript se actualiza muy raramente.
  4. Opera te permite controlar de manera flexible la actualización de imágenes, JavaScript y CSS usando la configuración de Verificar imágenes, que es una ventaja. Opera también se comporta mejor que IE & FF con el almacenamiento en caché habilitado y la actualización forzada, ya que, permítame recordarle, Opera actualiza completamente el contenido de la página en este caso, e IE & FF lo dejará en una feliz ignorancia.

Buena suerte y sitios rentables.

El almacenamiento en caché configurado correctamente proporciona enormes ganancias de rendimiento, ahorra ancho de banda y reduce los costos del servidor, pero muchos sitios no implementan bien el almacenamiento en caché, lo que crea una condición de carrera que hace que los recursos interconectados no estén sincronizados.

La gran mayoría de las mejores prácticas de almacenamiento en caché se encuadran en uno de dos patrones:

Patrón n. ° 1: contenido inmutable y larga antigüedad máxima de la caché

Control de caché: max-age = 31536000
  • El contenido de la URL no cambia, por lo tanto ...
  • El navegador o CDN puede almacenar en caché un recurso durante un año sin ningún problema
  • El contenido en caché que es más reciente que la edad máxima especificada se puede usar sin consultar al servidor

Página : Oye, necesito "/script-v1.js", "/styles-v1.css" y "/cats-v1.jpg" 10:24

Cache : Estoy vacío, ¿qué tal tu servidor? 10:24

Servidor : OK, ahí están. Por cierto, Cash, deberían usarse dentro de un año, no más. 10:25

Cache : ¡GRACIAS! 10:25

Página : ¡Hurra! 10:25

El día siguiente

Página : Oye, necesito "/ script- v2.js "," / styles- v2.css "y" /cats-v1.jpg "08:14

Cache : Hay una foto con gatos, el resto no. ¿Servidor? 08:14

Servidor : Fácil: aquí están los nuevos CSS y JS. Una vez más, Cash: su vida útil es de no más de un año. 08:15

Cache : ¡Súper! 08:15

Página : ¡Gracias! 08:15

Cache : Hmm, no he usado "/script-v1.js" & "/styles-v1.css" el tiempo suficiente. Es hora de eliminarlos. 12:32

Con este patrón, nunca cambia el contenido de una URL específica, cambia la URL en sí:

Cada URL tiene algo que cambia junto con el contenido. Puede ser un número de versión, una fecha de modificación o un hash del contenido (esta es la opción que elegí para mi blog).

La mayoría de los frameworks del lado del servidor tienen herramientas para hacer este tipo de cosas con facilidad (en Django utilizo Manifest Static Files Storage); También hay bibliotecas muy pequeñas en Node.js que hacen lo mismo, como gulp-rev.

Sin embargo, este patrón no es adecuado para cosas como artículos y publicaciones de blogs. Sus URL no se pueden versionar y su contenido puede cambiar. En serio, tengo muchos errores gramaticales y de puntuación y necesito poder actualizar rápidamente el contenido.

Patrón # 2: contenido mutable que siempre se revalida en el servidor

Control de caché: sin caché
  • El contenido de la URL cambiará, así que ...
  • No se puede utilizar ninguna versión local en caché sin especificar un servidor.

Página : Oye, necesito el contenido de "/ about /" y "/sw.js" 11:32

Cache : No puedo evitarlo. ¿Servidor? 11:32

Servidor : Los hay. Efectivo, guárdelos con usted, pero pregúnteme antes de usarlos. 11:33

Cache : ¡Sí señor! 11:33

Página : ¡GRACIAS! 11:33

El día siguiente

Página : Oye, necesito el contenido de "/ about /" y "/sw.js" nuevamente 09:46

Cache : Espera un minuto. Servidor, ¿están bien mis copias? Una copia de "/ about /" es del lunes y "/sw.js" es de ayer. 09:46

Servidor : "/sw.js" no ha cambiado ... 09:47

Cache : Frio. Página, mantén presionado "/sw.js". 09:47

Servidor : ... pero "/ about /" tengo una nueva versión. Efectivo, abrázala, pero como la última vez, recuerda preguntarme primero. 09:47

Cache : ¡Comprendido! 09:47

Página : ¡Multa! 09:47

Nota: sin caché no significa "no almacenar en caché", significa "verificar" (o revalidar) el recurso almacenado en caché del servidor. La no tienda ordena al navegador que no almacene en caché en absoluto. Además, must-revalidate no significa revalidación obligatoria, sino el hecho de que el recurso almacenado en caché se usa solo si es más joven que la edad máxima especificada, y solo de lo contrario se revalida. Así es como se inicia el almacenamiento en caché de palabras clave.

En este patrón, puede agregar ETag (ID de versión de su elección) o el encabezado Última modificación a la respuesta. En la siguiente solicitud de contenido del cliente, genera If-None-Match o If-Modified-Since, respectivamente, lo que permite que el servidor diga "Use lo que tiene, su caché está actualizado", que es devolver HTTP 304.

Si no es posible enviar ETag / Last-Modified, el servidor siempre envía todo el contenido.

Este patrón siempre requiere solicitudes de red, por lo que no es tan bueno como el primer patrón que puede funcionar sin solicitudes de red.

No es infrecuente cuando no tenemos la infraestructura para el primer patrón, pero también pueden surgir problemas con las solicitudes de red en el patrón 2. Como resultado, se usa una opción intermedia: un contenido corto de máxima edad y mutable. Este es un mal compromiso.

Usar max-age con contenido mutable suele ser una elección incorrecta.

Y, desafortunadamente, está muy extendido, las páginas de Github se pueden tomar como ejemplo.

Imagina:

  • / articulo /
  • /styles.css
  • /script.js

Con un encabezado del lado del servidor:

Control de caché: debe revalidar, edad máxima = 600

  • Cambios en el contenido de la URL
  • Si el navegador tiene una versión en caché fresca de 10 minutos, se usa sin consultar al servidor
  • Si no existe tal caché, se utiliza una solicitud de red, posiblemente con If-Modified-Since o If-None-Match

Página : Oye, necesito "/ article /", "/script.js" y "/styles.css" 10:21

Cache : ¿No tengo nada como tú, servidor? 10:21

Servidor : No hay problema, aquí están. Pero recuerde, Efectivo: se pueden usar en los próximos 10 minutos. 10:22

Cache : ¡Hay! 10:22

Página : ¡GRACIAS! 10:22

Página : Oye, necesito "/ article /", "/script.js" y "/styles.css" nuevamente 10:28

Cache : Vaya, lo siento, pero perdí "/styles.css", pero tengo todo lo demás, tómalo. Servidor, ¿puedes personalizar "/styles.css" para mí? 10:28

Servidor : Fácil, ya ha cambiado desde la última vez que lo recogió. Puede usarlo de manera segura durante los próximos 10 minutos. 10:29

Cache : No hay problema. 10:29

Página : ¡Gracias! ¡Pero parece que algo salió mal! ¡Todo está roto! ¿Qué está pasando? 10:29

Este patrón tiene derecho a vivir en pruebas, pero rompe todo en un proyecto real y es muy difícil de rastrear. En el ejemplo anterior, el servidor ha actualizado el HTML, CSS y JS, pero la página se muestra con el antiguo HTML y JS de la caché, a la que se ha agregado el CSS actualizado del servidor. El desajuste de versiones lo estropea todo.

A menudo, al realizar cambios significativos en HTML, cambiamos tanto el CSS para reflejar la nueva estructura correctamente como el JavaScript para mantenernos al día con el contenido y los estilos. Estos recursos son todos independientes, pero los encabezados de la caché no pueden expresar esto. Como resultado, los usuarios pueden tener la última versión de uno o dos recursos y una versión anterior del resto.

max-age se establece en relación con el tiempo de respuesta, por lo que si todos los recursos se transfieren como parte de la misma dirección, caducarán al mismo tiempo, pero todavía hay una pequeña posibilidad de desincronización. Si tiene páginas que no incluyen JavaScript o incluyen otros estilos, las fechas de vencimiento de su caché no estarán sincronizadas. Y lo que es peor, el navegador extrae constantemente contenido de la caché, sin saber que HTML, CSS y JS son interdependientes, por lo que puede sacar uno de la lista y olvidarse de todo lo demás. Teniendo en cuenta todos estos factores en conjunto, debe comprender que la probabilidad de que las versiones no coincidan es bastante alta.

Para el usuario, el resultado podría ser un diseño de página roto u otros problemas. Desde pequeños fallos hasta contenido completamente inutilizable.

Afortunadamente, los usuarios tienen una salida de emergencia ...

Actualizar la página a veces ahorra

Si la página se carga mediante actualización, los navegadores siempre realizan una revalidación del lado del servidor, ignorando la edad máxima. Por lo tanto, si el usuario tiene algo roto debido a la edad máxima, una simple actualización de la página puede arreglarlo todo. Pero, por supuesto, después de que se encuentren las cucharas, el sedimento permanecerá y la actitud hacia su sitio será algo diferente.

Un trabajador de servicios puede prolongar la vida de estos errores.

Por ejemplo, tiene un trabajador de servicios como este:

Versión constante = "2"; self.addEventListener ("instalar", event => (event.waitUntil (caches.open (`static - $ (versión)`). then (cache => cache.addAll (["/styles.css", "/ script .js "])));)); self.addEventListener ("activar", evento => (// ... eliminar cachés antiguos ...)); self.addEventListener ("fetch", event => (event.respondWith (caches.match (event.request) .then (response => response || fetch (event.request))));));

Este trabajador de servicio:

  • almacena en caché el script y los estilos
  • usa el caché en el partido, de lo contrario accede a la red

Si cambiamos el CSS / JS, también aumentamos el número de versión, lo que desencadena una actualización. Sin embargo, dado que addAll accede primero a la caché, podemos terminar en una condición de carrera debido a la edad máxima y las versiones de CSS y JS que no coinciden.

Después de que se almacenen en caché, tendremos CSS y JS incompatibles hasta la próxima actualización del service worker, y esto es así si nuevamente no entramos en una condición de carrera durante la actualización.

Puede omitir el almacenamiento en caché en el trabajador del servicio:

Self.addEventListener ("instalar", event => (event.waitUntil (caches.open (`static - $ (version)`) .then (cache => cache.addAll ([new Request ("/ styles.css", (caché: "sin caché")), nueva solicitud ("/ script.js", (caché: "sin caché"))])));));

Desafortunadamente, las opciones de almacenamiento en caché no son compatibles con Chrome / Opera y se acaban de agregar a la compilación nocturna de Firefox, pero puede hacerlo usted mismo:

Self.addEventListener ("instalar", event => (event.waitUntil (caches.open (`static - $ (version)`). Then (cache => Promise.all (["/styles.css", "/ script .js "] .map (url => (// cache-bust usando una cadena de consulta aleatoria return fetch (` $ (url)? $ (Math.random ()) `) .then (response => (// fail en 404, 500, etc. if (! response.ok) throw Error ("Not ok"); return cache.put (url, response);)))))))));));

En este ejemplo, estoy limpiando la caché con un número aleatorio, pero puede continuar y agregar un hash del contenido en la compilación (esto es similar a lo que hace sw-precache). Esta es una especie de implementación de JavaScript del primer patrón, pero solo funciona con un trabajador de servicio, no con navegadores ni CDN.

Service Workers y HTTP Cache funcionan muy bien juntos, ¡no los haga luchar!

Como puede ver, puede solucionar los errores de almacenamiento en caché en su trabajador de servicio, pero es mejor abordar la raíz del problema. Configurar el almacenamiento en caché correctamente no solo facilita el trabajo del trabajador del servicio, sino que también ayuda a los navegadores que no son compatibles con los trabajadores del servicio (Safari, IE / Edge) y también le permite aprovechar al máximo su CDN.

Los encabezados de almacenamiento en caché correctos también pueden facilitar la actualización del trabajador del servicio.

Versión constante = "23"; self.addEventListener ("instalar", event => (event.waitUntil (caches.open (`static - $ (versión)`). then (cache => cache.addAll (["/", "/ script-f93bca2c. js "," /styles-a837cb1e.css "," /cats-0e9a2ef4.jpg "])));));

Aquí he almacenado en caché la página raíz con el patrón n. ° 2 (revalidación del lado del servidor) y todos los demás recursos con el patrón n. ° 1 (contenido inmutable). Cada actualización del trabajador del servicio provocará una solicitud a la página raíz, y todos los demás recursos solo se cargarán si su URL ha cambiado. La buena noticia es que ahorra tráfico y mejora el rendimiento, ya sea que esté actualizando desde una versión anterior o una versión muy antigua.

Aquí hay una ventaja significativa sobre la implementación nativa, donde el binario completo se descarga incluso con un pequeño cambio, o invoca comparaciones binarias complejas. De esta forma podemos actualizar una gran aplicación web con una carga relativamente pequeña.

Los trabajadores de servicios funcionan mejor como una mejora en lugar de una muleta temporal, así que trabaje con el caché en lugar de luchar contra él.

Cuando se usa con cuidado, el contenido mutable y de máxima edad puede ser muy bueno.

max-age es muy a menudo la elección incorrecta para contenido mutable, pero no siempre. Por ejemplo, el artículo original tiene una antigüedad máxima de tres minutos. Las condiciones de carrera no son un problema ya que no hay dependencias en la página que usa el mismo patrón de almacenamiento en caché (CSS, JS e imágenes usan el patrón # 1 - contenido inmutable), todo lo demás no usa este patrón.

Este patrón significa que estoy escribiendo tranquilamente un artículo popular, y mi CDN (Cloudflare) puede aliviar la carga del servidor, si, por supuesto, estoy dispuesto a esperar tres minutos para que el artículo actualizado esté disponible para los usuarios.

Este patrón debe usarse sin fanatismo. Si agregué una nueva sección a un artículo y lo vinculé desde otro artículo, creé una dependencia que debe resolverse. El usuario puede hacer clic en el enlace y obtener una copia del artículo sin la sección que está buscando. Si quiero evitar esto, tengo que actualizar el artículo, eliminar la versión en caché del artículo de Cloudflare, esperar tres minutos y solo luego agregar el enlace a otro artículo. Sí, este patrón requiere precaución.

Cuando se usa correctamente, el almacenamiento en caché puede proporcionar un rendimiento significativo y ahorros de ancho de banda. Pase contenido inmutable si puede cambiar fácilmente la URL o use la revalidación del lado del servidor. Mezcle contenido mutable y de máxima edad si es lo suficientemente atrevido como para asegurarse de que su contenido no tenga dependencias que puedan desincronizarse.

Al incluir CSS y Javascript externos, queremos mantener al mínimo las solicitudes HTTP innecesarias.

Para ello, los archivos .js y .css se entregan con encabezados que proporcionan un almacenamiento en caché confiable.

Pero, ¿qué pasa si alguno de estos archivos cambia durante el desarrollo? Todos los usuarios tienen una versión anterior en la caché; hasta que la caché esté desactualizada, surgirán muchas quejas sobre la integración defectuosa del servidor y las partes del cliente.

La forma correcta de almacenamiento en caché y control de versiones elimina por completo este problema y garantiza una sincronización confiable y transparente de las versiones de estilo / script.

Almacenamiento en caché ETag fácil

La forma más sencilla de almacenar en caché los recursos estáticos es mediante ETag.

Es suficiente habilitar la configuración apropiada del servidor (para Apache está habilitada de manera predeterminada), y se le dará ETag a cada archivo en los encabezados, un hash que depende de la hora de actualización, el tamaño del archivo y (en los sistemas de archivos basados ​​en inodo ) inodo.

El navegador almacena en caché dicho archivo y, en solicitudes posteriores, especifica el encabezado If-None-Match de la ETag del documento en caché. Una vez recibido dicho encabezado, el servidor puede responder con un código 304, y luego el documento se tomará del caché.

Se parece a esto:

Primera solicitud al servidor (limpieza de caché) GET /misc/pack.js HTTP / 1.1 Host: sitio

En general, el navegador generalmente agrega un montón de encabezados como User-Agent, Accept, etc. Se cortan por brevedad.

Respuesta del servidor El servidor envía en respuesta un documento con código 200 y ETag: HTTP / 1.x 200 OK Codificación de contenido: gzip Tipo de contenido: texto / javascript; charset = utf-8 Etag: "3272221997" Rangos de aceptación: bytes Longitud del contenido: 23321 Fecha: viernes 02 de mayo de 2008 17:22:46 GMT Servidor: lighttpd Siguiente solicitud del navegador En la siguiente solicitud, el navegador agrega If-None-Match: (ETag en caché): GET /misc/pack.js HTTP / 1.1 Host: sitio If-None-Match: "453700005" Respuesta del servidor El servidor está buscando - sí, el documento no ha cambiado. Esto significa que puede emitir un código 304 y no volver a enviar el documento. HTTP / 1.x 304 No modificado Codificación de contenido: gzip Etag: "453700005" Tipo de contenido: texto / javascript; charset = utf-8 Accept-Ranges: bytes Fecha: martes, 15 de abril de 2008 10:17:11 GMT

Alternativamente, si el documento ha cambiado, el servidor simplemente envía 200 con una nueva ETag.

El paquete Last-Modified + If-Modified-Since funciona de manera similar:

  1. el servidor envía la fecha de la última modificación en el encabezado Última modificación (en lugar de ETag)
  2. el navegador almacena en caché el documento y, en la siguiente solicitud del mismo documento, envía la fecha de la versión en caché en el encabezado If-Modified-Since (en lugar de If-None-Match)
  3. el servidor verifica las fechas, y si el documento no ha cambiado, envía solo el código 304, sin contenido.

Estos métodos funcionan de manera estable y bien, pero el navegador tiene que hacerlo a pedido de todos modos para cada script o estilo.

Almacenamiento en caché inteligente. Control de versiones

El enfoque general para el control de versiones es en pocas palabras:

  1. La versión (o fecha de modificación) se agrega a todos los scripts. Por ejemplo, http: // sitio / my.js se convertirá en http: // site / my.v1.2.js
  2. Todos los scripts son almacenados en caché por el navegador.
  3. Cuando se actualiza el script, la versión cambia a una nueva: http: // site / my.v2.0.js
  4. La dirección ha cambiado, por lo que el navegador solicitará y almacenará en caché el archivo nuevamente.
  5. La antigua versión 1.2 saldrá gradualmente de la caché

Almacenamiento en caché duro

Almacenamiento en caché duro- una especie de mazo que clava completamente las solicitudes al servidor de documentos almacenados en caché.

Para hacer esto, simplemente agregue los encabezados Expires y Cache-Control: max-age.

Por ejemplo, para almacenar en caché durante 365 días en PHP:

Encabezado ("Caduca:" .gmdate ("D, d M Y H: i: s", hora () + 86400 * 365). "GMT"); encabezado ("Cache-Control: max-age =" + 86400 * 365);

O puede almacenar en caché el contenido durante mucho tiempo usando mod_header en Apache:

Habiendo recibido tales encabezados, el navegador guardará en caché el documento durante mucho tiempo. Todas las demás llamadas al documento se atenderán directamente desde la caché del navegador, sin contactar con el servidor.

La mayoría de los navegadores (Opera, Internet Explorer 6+, Safari) NO almacenan documentos en caché si hay un signo de interrogación en la dirección, porque se consideran dinámicos.

Es por eso que agregamos la versión al nombre del archivo. Por supuesto, con tales direcciones debe usar una solución como mod_rewrite, lo consideraremos más adelante en el artículo.

P.D .: Pero Firefox almacena en caché las direcciones con signos de interrogación.

Traducción automática de nombres

Veamos cómo cambiar versiones de forma automática y transparente sin cambiar el nombre de los archivos.

Nombre de la versión -> Archivo

Lo más simple es convertir el nombre versionado al nombre de archivo original.

A nivel de Apache, esto se puede hacer con mod_rewrite:

RewriteEngine en RewriteRule ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 [L]

Esta regla procesa todos los archivos css / js / gif / png / jpg, eliminando la versión del nombre.

Por ejemplo:

/images/logo.v2.gif -> /images/logo.gif
/css/style.v1.27.css -> /css/style.css
/javascript/script.v6.js -> /javascript/script.js

Pero además de cortar la versión, también necesita agregar encabezados en caché a los archivos. Para ello, se utilizan las directivas mod_header:

Encabezado agregar "Expires" "Lun, 28 de julio de 2014 23:30:00 GMT" Encabezado agregar "Cache-Control" "max-age = 315360000"

Y todos juntos implementan una configuración de apache de este tipo:

RewriteEngine on # elimina la versión y, al mismo tiempo, establece la variable que tiene la versión del archivo RewriteRule ^ / (. * \.) V + \. (Css | js | gif | png | jpg) $ / $ 1 $ 2 # archivos de versión de caché duro Encabezado agregar "Expires" "Lun, 28 de julio de 2014 23:30:00 GMT" env = VERSIONED_FILE Encabezado agregar "Cache-Control" "max-age = 315360000" env = VERSIONED_FILE

Debido a la forma en que funciona el módulo mod_rewrite, la RewriteRule debe colocarse en el archivo de configuración principal httpd.conf o en los archivos conectados a él, pero en ningún caso en .htaccess, de lo contrario los comandos de encabezado se ejecutarán primero, antes de variable instalada VERSIONED_FILE.

Las directivas de encabezado pueden estar en cualquier lugar, incluso en .htaccess, no hay diferencia.

Agregar automáticamente una versión al nombre del archivo en una página HTML

Cómo poner una versión en el nombre de un script depende de su sistema de plantillas y, en general, de cómo agrega los scripts (estilos, etc.).

Por ejemplo, cuando se usa la fecha de modificación como la versión y el motor de plantilla Smarty, los enlaces se pueden configurar así:

La función de versión agrega una versión:

Función smarty_version ($ args) ($ stat = stat ($ GLOBALS ["config"] ["site_root"]. $ Args ["src"]); $ versión = $ stat ["mtime"]; echo preg_replace ("! \. (+?) $! "," .v $ versión. \ $ 1 ", $ args [" src "]);)

Resultado en la página:

Mejoramiento

Para evitar llamadas estadísticas innecesarias, puede almacenar una matriz que enumere las versiones actuales en una variable separada.

$ versiones ["css"] = matriz ("grupo.css" => "1.1", "otro.css" => "3.0",)

En este caso, el HTML simplemente se sustituye por la versión actual de la matriz.

Puede cruzar ambos enfoques y emitir una versión por fecha de modificación durante el desarrollo, por relevancia y en producción, una versión de una matriz para el rendimiento.

Aplicabilidad

Este método de almacenamiento en caché funciona en todas partes, incluidos Javascript, CSS, imágenes, películas flash, etc.

Es útil cada vez que cambia el documento, pero el navegador siempre debe tener la versión actual actual.