Невозможно управлять статическими ресурсами с помощью Spring Webflux и Thymeleaf - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь реализовать статическое управление версиями контента в моем приложении, используя Spring Webflux, как описано в документации: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux-config-static-resources

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

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {

        final VersionResourceResolver versionResolver = new VersionResourceResolver();

        versionResolver.addFixedVersionStrategy("test_version", "/**");

        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/")
                .resourceChain(false)
                .addResolver(versionResolver);
    }

С этим кодом я ожидаю, что вся статистика будет храниться в "/ static /" в пути к классам, запрашиваемом браузером, с добавлением "test_version" в URL.

Однако из всех запрошенных ресурсовтолько несколько запросов выполняются с версией в URL.

Например, вот пример запрошенных изображений:

enter image description here

И вот единственное изображение, запрошенное с версией, добавленной в URL:

enter image description here

Мои ресурсы JS или CSS не имеют версий двух.Я не вижу различий на уровне HTTP (заголовки и т. Д.) Между версионным и неверсированным ресурсом, запустите из заголовка ETag.

Вот моя конфигурация проекта: Spring Boot 2.1.0.RELEASE with SpringWebflux, Thymeleaf 3.0.11.RELEASE, Netty server.

Есть ли причина, по которой некоторые из моих ресурсов обрабатываются VersionResourceResolver, а некоторые нет?

UPDATE

Я воспроизвел проблему на примере приложения: https://github.com/adsanche/statics-versioning-problem

Это приложение содержит только Webflux и Thymeleaf, запущенные с Spring Boot 2.1.0.RELEASE.

Вотмоя версия управления конфигурацией в application.yml:

spring:
  resources:
    chain:
      strategy:
        fixed:
          enabled: true
          version: test_version

Обратите внимание, что изображение, запрошенное через шаблон, не является версионным:

<!-- Can't version this image -->
<img th:src="@{/images/not_versioned.png}">

enter image description here

Тем не менее, изображение, запрошенное через CSS, имеет хорошую версию:

.test {
    background: url('/images/versioned.png');
}

enter image description here

Мой файл CSS, запрошенный как через Thymeleaf, не является версионнымтоже:

<head>
    <link rel="stylesheet" th:href="@{/css/main.css}"/>
</head>

То же самое с Sring Boot 2.1.1.RELEASE.

Я что-то упустил в конфигурации Spring Boot / Thymeleaf или это может быть проблемой?

ОБНОВЛЕНИЕ2

Я мог бы начать объяснение этого поведения.

Кажется, что ресурс, вызванный через файл CSS, имеет версию, поскольку существует CssLinkResourceTransformer, вызывающий getForUriString метод в ResourceUrlProvider, который использует VersionResourceResolver для разрешения пути к ресурсу.

Однако при вызове из шаблона SpringWebFluxTemplateEngine, кажется, разрешает путь к ресурсу через SpringWebFluxLinkBuilder,чей processLink метод, кажется, просто возвращает путь к ресурсу в том виде, в котором он указан, без преобразования или вызова ResourceUrlProvider.

Единственный обходной путь, который я нашел в данный момент, - переопределить SpringWebFluxLinkBuilder thisи установив его на SpringWebFluxTemplateEngine:

@Override
public String processLink(IExpressionContext context, String link) {

    return super.processLink(context, "test_version" + link);
}

С этим кодом я могу создавать версии всех CSS / JS / изображений, вызываемых в шаблоне.Тем не менее, я хотел бы знать, если это необходимо или мне просто не хватает какой-либо точки конфигурации для автоматического запуска этой логики.

1 Ответ

0 голосов
/ 17 декабря 2018

Во-первых, вы должны удалить свою пользовательскую конфигурацию и полагаться на свойства конфигурации, поскольку вы ничего не делаете, чего уже достиг Spring Boot:

spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.version=test_version

Ресурсные URL-адреса переписываются на стороне сервера ресурсомподдержка обработки в Spring Framework.

Сначала убедитесь, что она включена:

  1. В случае Spring Boot у вас не должно быть @EnableWebMvc или @EnableWebFlux, поскольку они отключают автоматическую настройку в сети
  2. Ссылки на ресурсы должны находиться в файле шаблона или в файле, который переписан Spring (например, файл CSS)
  3. URL-адреса ресурсов должныбыть закодирован механизмом шаблонов, например <link rel="stylesheet" th:href="@{/static/css/spring.css}">

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

Вы можете видеть, что контракт ResourceUrlProvider является асинхронным, поскольку он возвращает тип Mono.С другой стороны, SpringWebFluxLinkBuilder ожидает блокирующий контракт.Я не говорю, что здесь виноват Thymeleaf, так как Thymeleaf уже отрисовывает шаблон реактивным способом.Но для рендеринга этих ссылок нам необходимо прочитать весь ресурс и вычислить его хеш - и мы не можем сделать это в середине рендеринга шаблона.

Подробнее об этом можно прочитать в SPR-15012 , который объясняет текущее состояние вещей.Не стесняйтесь комментировать этот тикет - возможно, что-то изменилось за это время, или что-то может отсутствовать в справочной документации Spring Framework / Spring Boot.

...