Actifs statiques cachables avec Spring MVC

Actifs statiques pouvant être mis en cache avec Spring MVC

1. Vue d'ensemble

Cet article traite de la mise en cache des ressources statiques (telles que les fichiers Javascript et CSS) lors de leur utilisation avec Spring MVC.

Nous aborderons également le concept de «mise en cache parfaite», en veillant essentiellement à ce que, lorsqu'un fichier est mis à jour, l'ancienne version ne soit pas diffusée de manière incorrecte à partir du cache.

2. Mise en cache des actifs statiques

Afin de rendre les actifs statiques pouvant être mis en cache, nous devons configurer le gestionnaire de ressources correspondant.

Voici un exemple simple de la façon de procéder: définir l'en-têteCache-Control de la réponse surmax-age=31536000, ce qui oblige le navigateur à utiliser la version mise en cache du fichier pendant un an:

@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**")
                .addResourceLocations("/js/")
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }
}

La raison pour laquelle nous avons une période de validité du cache si longue est que nous voulons que le client utilise la version mise en cache du fichier jusqu'à ce que le fichier soit mis à jour, et 365 jours est le maximum que nous pouvons utiliser selon lesRFC for the Cache-Control header.

And so, when a client requests foo.js for the first time, il recevra l'intégralité du fichier sur le réseau (37 octets dans ce cas) avec un code d'état de200 OK. La réponse aura l'en-tête suivant pour contrôler le comportement de la mise en cache:

Cache-Control: max-age=31536000

Le navigateur mettra alors le fichier en cache avec une durée d'expiration d'un an, à la suite de la réponse suivante:

cache

When the client requests the same file for the second time, le navigateur ne fera pas une autre requête au serveur. Au lieu de cela, il servira directement le fichier à partir de son cache et évitera les allers-retours sur le réseau afin que la page se charge beaucoup plus rapidement:

cache-highlighted

Les utilisateurs de navigateur Chrome doivent faire preuve de prudence lors des tests, car Chrome n'utilisera pas le cache si vous actualisez la page en appuyant sur le bouton d'actualisation à l'écran ou en appuyant sur la touche F5. Vous devez appuyer sur Entrée dans la barre d'adresse pour observer le comportement de la mise en cache. Plus d'informations sur ceshere.

3. Gestion des versions des actifs statiques

L'utilisation d'un cache pour servir les actifs statiques accélère le chargement de la page, mais il y a une mise en garde importante. Lorsque vous mettez à jour le fichier, le client ne recevra pas la version la plus récente du fichier car il ne vérifie pas auprès du serveur si le fichier est à jour et ne sert que le fichier à partir du cache du navigateur.

Voici ce que nous devons faire pour que le navigateur récupère le fichier du serveur uniquement lorsque le fichier est mis à jour:

  • Servir le fichier sous une URL comportant une version. Par exemple,foo.js doit être servi sous/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js

  • Mettre à jour les liens vers le fichier avec la nouvelle URL

  • Mettre à jour la partie de la version de l'URL chaque fois que le fichier est mis à jour. Par exemple, lorsquefoo.js est mis à jour, il doit maintenant être servi sous/js/foo-a3d8d7780349a12d739799e9aa7d2623.js.

Le client demandera le fichier au serveur lors de sa mise à jour car la page aura un lien vers une URL différente, de sorte que le navigateur n'utilisera pas son cache. Si un fichier n'est pas mis à jour, sa version (donc son URL) ne changera pas et le client continuera à utiliser le cache pour ce fichier.

Normalement, nous aurions besoin de toutes ces tâches manuellement, mais Spring les prend en charge immédiatement, notamment en calculant le hachage de chaque fichier et en les ajoutant aux URL. Voyons comment nous pouvons configurer notre application Spring pour faire tout cela pour nous.

3.1. Servir sous une URL avec une version

Nous devons ajouter unVersionResourceResolver à un chemin afin de servir les fichiers sous celui-ci avec une chaîne de version mise à jour dans son URL:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/js/**")
            .addResourceLocations("/js/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
            .resourceChain(false)
            .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}

Ici, nous utilisons une stratégie de version de contenu. Chaque fichier du dossier/js sera servi sous une URL dont la version est calculée à partir de son contenu. Ceci s'appelle l'empreinte digitale. Par exemple,foo.js sera désormais diffusé sous l'URL/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js.

Avec cette configuration, lorsqu'un client fait une demande pourhttp://localhost:8080/js/_46944c7e3a9bd20cc30fdc085cae46f2.js:_

curl -i http://localhost:8080/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js

Le serveur répondra par un en-tête Cache-Control pour indiquer au navigateur client de mettre le fichier en cache pendant un an:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Last-Modified: Tue, 09 Aug 2016 06:43:26 GMT
Cache-Control: max-age=31536000

Avant d'insérer la version dans l'URL, nous pourrions utiliser une simple balisescript pour importerfoo.js: