http - must - if-modified-since vs if-none-match
http cache (7)
¿Cuál podría ser la diferencia entre if-modified-since y if-none-match? Tengo la sensación de que if-none-match se usa para los archivos mientras que if-modified-since se usa para las páginas?
A menos que el servidor lo indique como débil, un ETag se considera un validador fuerte y, por lo tanto, se puede usar para satificar una solicitud condicional a distancia. Sin embargo, la mayoría de ETags generados automáticamente presentan dificultades en situaciones de granjas de servidores, ya que a menudo usan información de inodos y / o un único contador persistente. En la práctica, he encontrado que el encabezado Last Modified es suficiente para contenido bastante estático, por ejemplo, para servir contenido estático protegido, ya que el tiempo de escritura del archivo es un validador razonablemente bueno.
El ETag es de lejos el más flexible. Los clientes conformes deben enviar el ETag en una solicitud condicional, mientras que DEBEN enviar ambos si están disponibles.
Como se afirma en las mejores prácticas de Google:
Es importante especificar uno de Expira o Cache-Control max-age, y uno de Last-Modified o ETag, para todos los recursos cacheables. Es redundante especificar Caducidad y Control de caché: max-age, o para especificar Last-Modified y ETag.
https://developers.google.com/speed/docs/best-practices/caching
Dado que los bots de Google y Bing usan If-Modified-Since
y not If-None-Match
, es bueno apoyarlo.
Hay una manera de admitir If-Modified-Since
incluso en páginas complejas sin hacer un seguimiento de los tiempos de modificación. Usamos este método en WikiMentions.com . Este método hace muchas suposiciones sobre la configuración. Puede no funcionar para todos.
El html prestado debe ser una función pura de los datos devueltos por las llamadas de API. Considere una página de ejemplo example.com/shows/cosmos
. Puede necesitar más de una llamada de API:
api.example.com/shows/cosmos
api.example.com/cast/cosmos
api.example.com/related/cosmos
api.example.com/featured
Si cada llamada devuelve un etag, entonces podría generar un etag para su página html concatenando estos etags y procesando el resultado. A continuación, puede usar esto como etag para la página html. A continuación, puede almacenar este etag en memcached junto con la hora en que se creó y el html generado.
{
“Modified”: timestamp,
“Content”: rendered page,
“E-tag”: hash of concatenated etags of api calls
}
Ahora cuando se solicita una página por primera vez:
- Hacer llamadas de API para la página
- Generar etag concatenado
- Lookup etag en memcached (no existirá)
- Renderiza la página
- Agrégalo a memcached
- Enviarlo al usuario
Cuando una página es solicitada nuevamente por otro visitante nuevo:
- Hacer llamadas de API para la página
- Generar etag concatenado
- Lookup etag en memcached (existirá)
- Enviar copia en caché de una visita anterior
Cuando un visitante que regresa solicita una página (con If-Modified-Since):
- Hacer llamadas de API para la página
- Generar etag concatenado
- Lookup etag en memcached (existirá)
- Si el tiempo de modificación en memcached es posterior a If-Modified-Since
- Enviar copia en caché
- Más
- Enviar un 304 no modificado
Ventajas:
- Puede admitir
If-Modified-Since
yIf-None-Match
. - No hay páginas de re-renderización para nuevos visitantes si ya se procesaron antes.
- Nunca sirva contenido obsoleto.
Advertencias:
- No es necesario obtener el html renderizado de memcached si vamos a enviar un 304. Por lo tanto, puede almacenarlo por separado en memcached con un prefijo adjunto al etag como clave.
- Cuando cambias tu código de representación, los datos de la API no cambian, pero tu html renderizado sí lo hace. Como resultado, no podrá ver sus cambios ya que solo verá html en caché. Para evitar esto, necesitas generar una pequeña cadena aleatoria cada vez que construyas y anexas a los etags antes de hash.
- Esto no funcionará si el html renderizado no es una función pura de los datos api (por ej .: cadenas timeago). Una solución que utilizamos en WikiMentions es procesar las marcas de tiempo de gmt y convertirlas en timeago en el lado del cliente después de que se cargue React.
Esto puede no funcionar para todos dependiendo de la configuración. Funciona para nosotros Usamos tornado para nuestra API y Reaccionamos con Node.js para nuestro front-end.
El valor de marca de tiempo utilizado en Last-Modified / If-Modified-Since tiene una precisión limitada: un segundo y eso simplemente no es suficiente para un contenido de cambio rápido como, por ejemplo, la aplicación de chat web donde se puede publicar más de un mensaje en un segundo . ETag / If-None-Match puede ayudar a resolver ese problema.
If-Modified-Since
se compara con Last-Modified
mientras que If-None-Match
se compara con ETag
. Tanto Modified-Since
como ETag
se pueden usar para identificar una variante específica de un recurso.
Pero la comparación de If-Modified-Since
a Last-Modified
le proporciona la información de si la variante en caché es más antigua o más reciente, mientras que la comparación de If-None-Match
con ETag
solo le proporciona la información de si ambas son idénticas o no. Además, la mayoría de los generadores ETag
incluyen la información del inode específico del sistema, por lo que mover un archivo a una unidad diferente también puede cambiar la ETag
.
If-Modified-Since utiliza una fecha, mientras que If-None-Match usa una ETag . Ambos se pueden usar para "páginas" (es decir, HTML) y otros archivos.
En cuanto a las diferencias entre Last-Modified/If-Modified-Since
y ETag/If-None-Match
:
Ambos pueden usarse indistintamente. Sin embargo, dependiendo del tipo de recurso y cómo se genera en el servidor, una u otra pregunta ("¿esto ha sido modificado desde ...?" / "¿Esto aún coincide con este ETag?") Puede ser más fácil de responder .
Ejemplos:
- Si está publicando archivos, usar el
mtime
del archivo como la fecha deLast-Modified
es la solución más simple. - Si está sirviendo una página web dinámica construida a partir de una serie de consultas SQL, comprobar si los datos devueltos por cualquiera de esas consultas ha cambiado puede ser poco práctico (a menos que todos ellos tengan algún tipo de columna de "última modificación"). En este caso, usar p.ej. un hash md5 del contenido de la página como
ETag
será mucho más fácil.
OTOH, esto significa que todavía tiene que generar toda la página en el servidor, incluso para un GET condicional. Averiguar qué tiene que entrar exactamente en el ETag (claves primarias, números de revisión, ... etc.) puede ahorrarle mucho tiempo aquí.
Vea estos enlaces para más detalles sobre el tema: