Cachbare statische Assets mit Spring-MVC

Cacheable Static Assets mit Spring MVC

1. Überblick

Dieser Artikel befasst sich mit der Zwischenspeicherung statischer Elemente (z. B. JavaScript- und CSS-Dateien), wenn diese mit Spring MVC bereitgestellt werden.

Wir werden auch auf das Konzept des "perfekten Caching" eingehen und im Wesentlichen sicherstellen, dass beim Aktualisieren einer Datei die alte Version nicht fälschlicherweise aus dem Cache bereitgestellt wird.

2. Zwischenspeichern statischer Assets

Damit statische Assets zwischengespeichert werden können, müssen Sie den entsprechenden Ressourcenhandler konfigurieren.

Hier ist ein einfaches Beispiel dafür: Setzen Sie den HeaderCache-Control in der Antwort aufmax-age=31536000, wodurch der Browser die zwischengespeicherte Version der Datei ein Jahr lang verwendet:

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

Der Grund dafür, dass wir einen so langen Zeitraum für die Gültigkeit des Caches haben, ist, dass der Client die zwischengespeicherte Version der Datei verwenden soll, bis die Datei aktualisiert wird. 365{'t0': 'RFC for the Cache-Control header'}ind das Maximum, das wir gemäßRFC for the Cache-Control header verwenden können.

And so, when a client requests foo.js for the first time erhält er die gesamte Datei über das Netzwerk (in diesem Fall 37 Byte) mit dem Statuscode200 OK.. Die Antwort hat den folgenden Header, um das Caching-Verhalten zu steuern:

Cache-Control: max-age=31536000

Dies führt dazu, dass der Browser die Datei mit einer Ablaufdauer von einem Jahr zwischenspeichert, was auf die folgende Antwort zurückzuführen ist:

cache

When the client requests the same file for the second time, der Browser stellt keine weitere Anfrage an den Server. Stattdessen wird die Datei direkt aus dem Cache bereitgestellt und das Netzwerk-Roundtrip vermieden, sodass die Seite viel schneller geladen wird:

cache-highlighted

Benutzer von Chrome-Browsern müssen beim Testen vorsichtig sein, da Chrome den Cache nicht verwendet, wenn Sie die Seite durch Drücken der Schaltfläche Aktualisieren auf dem Bildschirm oder durch Drücken der Taste F5 aktualisieren. Sie müssen die Eingabetaste in der Adressleiste drücken, um das Caching-Verhalten zu beobachten. Weitere Infos zu diesemhere.

3. Versionierung statischer Assets

Durch die Verwendung eines Caches für die Bereitstellung der statischen Assets wird die Seite zwar sehr schnell geladen, weist jedoch eine wichtige Einschränkung auf. Wenn Sie die Datei aktualisieren, erhält der Client nicht die neueste Version der Datei, da er nicht mit dem Server überprüft, ob die Datei aktuell ist und nur die Datei aus dem Browser-Cache bereitstellt.

Folgendes müssen wir tun, damit der Browser die Datei nur dann vom Server erhält, wenn die Datei aktualisiert wird:

  • Stellen Sie die Datei unter einer URL bereit, die eine Version enthält. Zum Beispiel solltenfoo.js unter/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js serviert werden

  • Aktualisieren Sie die Links zur Datei mit der neuen URL

  • Aktualisieren Sie die Version eines Teils der URL, wenn die Datei aktualisiert wird. Wenn beispielsweisefoo.js aktualisiert wird, sollte es jetzt unter/js/foo-a3d8d7780349a12d739799e9aa7d2623.js. bereitgestellt werden

Der Client fordert die Datei beim Aktualisieren vom Server an, da die Seite einen Link zu einer anderen URL enthält, sodass der Browser den Cache nicht verwendet. Wenn eine Datei nicht aktualisiert wird, ändert sich ihre Version (daher ihre URL) nicht und der Client verwendet weiterhin den Cache für diese Datei.

Normalerweise müssten wir dies alles manuell tun, aber Spring unterstützt dies sofort, einschließlich der Berechnung des Hashs für jede Datei und des Anhängens dieser an die URLs. Mal sehen, wie wir unsere Spring-Anwendung so konfigurieren können, dass sie all dies für uns erledigt.

3.1. Unter einer URL mit einer Version dienen

Wir müssen einem Pfad einVersionResourceResolver hinzufügen, um die Dateien darunter mit einer aktualisierten Versionszeichenfolge in der URL bereitzustellen:

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

Hier verwenden wir eine Inhaltsversionsstrategie. Jede Datei im Ordner/jswird unter einer URL bereitgestellt, deren Inhalt eine Version berechnet. Dies wird als Fingerabdruck bezeichnet. Beispielsweise wirdfoo.js jetzt unter der URL/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js. bereitgestellt

Bei dieser Konfiguration, wenn ein Client eine Anforderung fürhttp://localhost:8080/js/_46944c7e3a9bd20cc30fdc085cae46f2.js:_ stellt

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

Der Server antwortet mit einem Cache-Control-Header, um den Client-Browser anzuweisen, die Datei für ein Jahr zwischenzuspeichern:

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

Bevor wir die Version in die URL einfügen, können wir ein einfachesscript-Tag verwenden, umfoo.js zu importieren: