Рубрики
Без рубрики

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

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

Автор оригинала: baeldung.

1. Обзор

Эта статья посвящена кэшированию статических ресурсов (таких как файлы Javascript и CSS) при их обслуживании с помощью Spring Boot и 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 для Cache-Control header .

И так, когда клиент запрашивает foo.js в первый раз он получит весь файл по сети (в данном случае 37 байт) с кодом состояния 200 OK. Ответ будет иметь следующий заголовок для управления поведением кэширования:

Cache-Control: max-age=31536000

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

кэш

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

выделенный кэш

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

2.1. Пружинный ботинок

Чтобы настроить заголовки Cache-Control в Spring Boot, мы можем использовать свойства в пространстве имен spring.resources.cache.cachecontrol | property. Например, чтобы изменить max-age на один год, мы можем добавить следующее в наш application.properties :

spring.resources.cache.cachecontrol.max-age=365d

Это относится к всем статическим ресурсам , обслуживаемым Spring Boot . Поэтому, если мы просто хотим применить стратегию кэширования к подмножеству запросов, мы должны использовать простой подход Spring MVC.

В дополнение к max-age, также можно настроить другие Cache-Control параметры , такие как no-store или no-cache с аналогичными свойствами конфигурации.

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

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

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

3.2. Пружинный ботинок

Чтобы включить такое же управление версиями на основе содержимого в Spring Boot, нам просто нужно использовать несколько конфигураций в пространстве имен spring.resources.chain.strategy.content property. Например, мы можем достичь того же результата, что и раньше, добавив следующие конфигурации:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

Аналогично конфигурации Java, это позволяет управлять версиями на основе содержимого для всех ресурсов, соответствующих шаблону пути /**|/.

3.3. Обновите Ссылки С Новым URL-адресом

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