Symfony 2.4, el libro oficial

14.3. Introducción a la caché de HTTP

Para aprovechar todas las capas de caché disponibles, tu aplicación debe poder comunicar qué respuestas son cacheables y las condiciones que se deben cumplir para que la respuesta cacheada siga considerándose válida. Esto se consigue añadiendo cabeceras HTTP de caché en la respuesta.

Truco Ten en cuenta que HTTP no es más que el lenguaje (un lenguaje simple de texto) que los clientes web (navegadores, por ejemplo) y los servidores web utilizan para comunicarse entre sí. Cuando hablamos de la caché HTTP, estamos hablando de la parte de ese lenguaje que permite a los clientes y servidores intercambiar información relacionada con la caché.

HTTP especifica las siguientes cuatro cabeceras relacionadas con la caché:

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

La cabecera más importante y versátil es la cabecera Cache-Control, que en realidad permite establecer muchas opciones relacionadas con la caché.

14.3.1. La cabecera Cache-Control

La cabecera Cache-Control es única porque no sólo permite establecer una opción de configuración de caché sino varias. Cada opción está separada por una coma:

Cache-Control: private, max-age=0, must-revalidate

Cache-Control: max-age=3600, must-revalidate

Symfony permite establecer los valores de la cabecera Cache-Control mediante una interfaz sencilla orientada a objetos:

// ...

use Symfony\Component\HttpFoundation\Response;

$response = new Response();

// indica si la respuesta es pública o privada
$response->setPublic();
$response->setPrivate();

// establece la duración máxima de la caché privada o compartida
$response->setMaxAge(600);
$response->setSharedMaxAge(600);

// establece una directiva Cache-Control concreta
$response->headers->addCacheControlDirective('must-revalidate', true);

14.3.2. Respuestas públicas y privadas

Tanto las gateway cache como las proxy cache se considean cachés compartidas porque el contenido guardado en caché se comparte con más de un usuario. Si por error estas cachés almacenan alguna vez información privada del usuario, se servirá la misma información privada a todos los usuarios. ¡Imagina que la información de tu cuenta se guarda en caché y luego se devuelve a cualquier usuario posterior que solicite la página de su cuenta!

Para resolver esta situación, cada respuesta puede indicar si es pública o privada:

  • public: indica que la respuesta se puede guardar en cualquier caché privadas o compartidas.
  • private: indica que toda o parte de la respuesta es exclusiva para un solo usuario y no se debe guardar en una caché compartida.

Symfony por defecto considera que todas las respuestas son privadas. Para aprovechar las ventajas de las cachés compartidas (como el proxy inverso de Symfony2), tendrás que indicar explícitamente que la respuesta es pública.

14.3.3. Métodos seguros

La caché HTTP sólo funciona para métodos HTTP seguros (como GET y HEAD). Un método seguro es aquél que nunca cambia de estado la aplicación en el servidor al servir la petición (por supuesto sí que puedes guardar información de log, etc.) Esto tiene dos consecuencias que son bastante lógicas:

  • Nunca debes cambiar el estado de tu aplicación al responder a una petición GET o HEAD. Incluso si no utilizas una gateway cache, la presencia del proxy cache significa que las peticiones GET o HEAD pueden llegar al servidor o no.
  • No esperes que haya métodos PUT, POST o DELETE en la caché. Estos métodos están diseñados para utilizarse cuando modificas el estado de tu aplicación (por ejemplo, al borrar una entrada del blog). Si estos métodos se cachearan, el resultado sería que algunas peticiones que modifican el estado de la aplicación nunca llegarían a la aplicación.

14.3.4. Reglas de caché y valores predeterminados

HTTP 1.1 por defecto permite guardar en la caché cualquier recurso a menos que incluya una cabecera Cache-Control. En la práctica, la mayoría de las cachés no hacen nada cuando las peticiones tienen una cookie, una cabecera de autorización, utilizan un método no seguro (es decir, PUT, POST, DELETE), o cuando las respuestas tienen un código de estado de redirección.

Cuando la aplicación no establece ninguna cabecera Cache-Control, Symfony2 añade esta cabecera aplicando las siguientes reglas:

  • Si no has definido ninguna cabecera relacionada con la caché (Cache-Control, Expires, ETag o Last-Modified), Cache-Control se establece a no-cache, lo que significa que la respuesta no se guarda en la caché.
  • Si la cabecera Cache-Control está vacía pero utilizas alguna de las otras cabeceras de caché, su valor se establece a private, must-revalidate.
  • Si al menos una directiva de Cache-Control está establecida, y no se han añadido directivas public o private de forma explícita, Symfony2 añade la directiva private automáticamente (excepto cuando utilizas s-maxage).