Кэшируемые статические активы с Spring MVC

Кэшируемые статические активы с помощью Spring MVC

1. обзор

В этой статье основное внимание уделяется кэшированию статических ресурсов (таких как файлы Javascript и CSS) при их обслуживании в Spring MVC.

Мы также коснемся концепции «идеального кеширования», по сути, убедившись, что при обновлении файла старая версия не будет неправильно загружена из кеша.

2. Кеширование статических активов

Чтобы сделать кэшируемые статические активы, нам нужно настроить соответствующий обработчик ресурсов.

Вот простой пример того, как это сделать - установка заголовкаCache-Control в ответ наmax-age=31536000, который заставляет браузер использовать кешированную версию файла в течение одного года:

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

Причина, по которой у нас такой длительный период действия кеша, заключается в том, что мы хотим, чтобы клиент использовал кешированную версию файла до тех пор, пока файл не будет обновлен, а 365 дней - это максимум, который мы можем использовать в соответствии сRFC for the Cache-Control header.

And so, when a client requests foo.js for the first time, он получит весь файл по сети (в данном случае 37 байт) с кодом состояния200 OK.. Ответ будет иметь следующий заголовок для управления поведением кэширования:

Cache-Control: max-age=31536000

Это приведет к тому, что браузер кеширует файл со сроком годности в результате следующего ответа:

cache

When the client requests the same file for the second time, браузер не будет делать другого запроса к серверу. Вместо этого он будет напрямую обслуживать файл из своего кэша и избегать обхода по сети, поэтому страница будет загружаться намного быстрее:

cache-highlighted

Пользователи браузера Chrome должны быть осторожны при тестировании, потому что Chrome не будет использовать кеш, если вы обновляете страницу, нажимая кнопку обновления на экране или клавишу F5. Вам нужно нажать ввод в адресной строке, чтобы наблюдать за поведением кэширования. Подробнее об этомhere.

3. Управление версиями статических активов

Использование кеша для обслуживания статических ресурсов делает загрузку страницы действительно быстрой, но имеет важное предостережение. Когда вы обновляете файл, клиент не получит самую последнюю версию файла, так как он не проверяет сервер на предмет актуальности файла и просто передает файл из кэша браузера.

Вот что нам нужно сделать, чтобы браузер получал файл с сервера только при обновлении файла:

  • Подайте файл по URL, в котором есть версия. Например,foo.js должен обслуживаться под/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js

  • Обновить ссылки на файл с новым URL

  • Обновлять версию версии URL при каждом обновлении файла. Например, при обновленииfoo.js он теперь должен обслуживаться в/js/foo-a3d8d7780349a12d739799e9aa7d2623.js.

Клиент запросит файл у сервера при его обновлении, потому что на странице будет ссылка на другой URL-адрес, поэтому браузер не будет использовать свой кеш. Если файл не обновляется, его версия (следовательно, его URL) не изменится, и клиент продолжит использовать кэш для этого файла.

Обычно нам нужно было бы делать все это вручную, но Spring поддерживает их сразу после установки, включая вычисление хеш-функции для каждого файла и добавление их в URL-адреса. Давайте посмотрим, как мы можем настроить наше приложение Spring для выполнения всего этого за нас.

3.1. Показывать по URL с версией

Нам нужно добавитьVersionResourceResolver к пути, чтобы обслуживать файлы под ним со строкой обновленной версии в его URL:

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

Здесь мы используем стратегию версии контента. Каждый файл в папке/js будет обслуживаться по URL-адресу, версия которого вычисляется на основе его содержимого. Это называется дактилоскопией. Например,foo.js теперь будет обслуживаться по URL-адресу/js/foo-46944c7e3a9bd20cc30fdc085cae46f2.js.

В этой конфигурации, когда клиент делает запросhttp://localhost:8080/js/_46944c7e3a9bd20cc30fdc085cae46f2.js:_

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

Сервер ответит заголовком Cache-Control, чтобы указать клиентскому браузеру кэшировать файл на год:

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

Прежде чем мы вставили версию в URL-адрес, мы могли использовать простой тегscript для импортаfoo.js: