Gestion du cache HTTP avec Symfony2
7Avant de vous lancer dans la lecture de cet article, je vous conseille de lire la documentation Symfony concernant le cache. Comme d'habitude c'est assez clair, et ça me permet de ne pas avoir à tout vous expliquer :).
Pour ce blog, la stratégie que j'ai adoptée est la suivante : lors de l'affichage d'un article, j'utilise la date de dernière modification de celui-ci pour définir l'en-tête HTTP "Last-Modified". Si dans la requête je vois que le client a déjà cette version en cache, je peux arrêter le traitement et retourner le code HTTP 304 "Not Modified". Dans le cas contraire, je continue le traitement pour servir la page au client, qui au passage la stockera en cache pour un éventuel futur appel.
Niveau code, voilà ce que ça donne dans mon contrôleur :
public function displayAction(Post $post) { $response = new Response(); $response->setLastModified($post->getModificationDate()); $response->setPublic(); if ($response->isNotModified($this->getRequest())) { return $response; // this will return the 304 if the cache is OK } // Do some stuff here... return $this->render('...:display.html.twig', array( 'post' => $post, // ... ), $response); }
Les 3 premières lignes permettent de définir la stratégie utilisée pour la gestion du cache. Notez l'appel à setPublic()
pour définir que le cache est commun à tous les utilisateurs, et non pas propre à l'utilisateur courant. Cela permet aux caches partagés (c'est-à-dire les proxy caches et les gateway caches) de stocker le cache également. Ainsi, si un utilisateur A a déjà affiché un article, un utilisateur B pourra profiter du cache qui a été généré pour l'utilisateur A, sans re-générer toute la page. Dans mon cas, c'est Symfony2 qui joue le rôle de gateway cache.
Ensuite, j'appelle la méthode $response->isNotModified()
en passant la requête en paramètre. C'est donc le framework qui va décider si on retourne un code 304 ou non, en comparant la date du header "Last-Modified" (que l'on vient de définir) à la date du header "If-Modified-Since" envoyé par le client (date de la version qu'il a dans son cache). Si l'article n'a pas été modifié depuis sa mise en cache, on n'a plus qu'à retourner l'objet réponse, qui représente alors le fameux code 304 "Not Modified".
Dans le cas contraire, on poursuit le traitement du contrôleur. Dans mon cas il s'agit principalement de préparer le formulaire pour l'ajout de commentaires... Enfin je traite mon template, en n'oubliant de passer mon objet $response
en 3e paramètre de $this->render()
, afin que le header "Last-Modified" soit bien ajouté à la réponse pour la mise en cache ; si vous oubliez ce dernier point, Symfony va créer un nouvel objet Response
standard, sans header pour la gestion du cache, et donc nos clients ne stockeront jamais notre page en cache !
Prochainement, je vous parlerai des "edge side includes" pour gérer le cache de la colonne de gauche de mon blog, et aussi des event listeners pour gérer la date de modification des articles en prenant en compte les commentaires...
A bientôt !
Commentaires (7)
J'ai remarqué hier qu'après avoir posté un commentaire sur un article, le compteur de commentaires de la page d'accueil du blog ne répercute pas de suite ce commentaire. Je suppose que sur cette page d'accueil du blog, tu as un rechargement automatique toutes les X minutes ?
PS: si on pouvait faire mémoriser nos coordonnées pour les commentaires ça serait top !
PS2: quand j'envoie mon commentaire, j'ai l'erreur "Le jeton CSRF est invalide. Veuillez renvoyer le formulaire.". Il faut que je le renvoie pour que ça passe.
Pour le PS2, le jeton CSRF est lui aussi mis en cache, ce qui provoque cette erreur... Je vais voir comment gérer ça.
Pour le PS1, là aussi le cache me met des bâtons dans le roues pour gérer ça... :)
On dirait que c'est le navigateur qui est à l'origine de ce comportement. Un F5 et l'information est mise à jour...
Je ne me suis pas encore penché sur la problématique, mais c'est dans cette direction que je partirai avant tout.