无法使用Spring Webflux和Thymeleaf对静态资源进行版本控制

时间:2018-12-14 17:31:59

标签: java spring spring-boot thymeleaf spring-webflux

我尝试使用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);
    }

使用此代码,我希望浏览器在URL中添加“ test_version”后,将所有静态信息存储到类路径中的“ / static /”中。

但是,在请求的所有资源中,只有少数请求是使用URL中的版本完成的。

例如,这是所请求图像的示例:

enter image description here

这是请求的唯一带有URL中添加的版本的图像:

enter image description here

我的JS或CSS资源没有版本化两个。在ETag标头中,我没有看到版本化资源和未版本化资源在HTTP级别(标头等)之间的任何区别。

这是我的项目配置:带有Spring Webflux的Spring Boot 2.1.0.RELEASE,Thymeleaf 3.0.11.RELEASE,Netty服务器。

为什么我的某些资源由VersionResourceResolver处理,而有些则没有?

更新

我在一个示例应用程序上重现了该问题:https://github.com/adsanche/statics-versioning-problem

此应用程序仅包含从Spring Boot 2.1.0.RELEASE开始的Webflux和Thymeleaf。

这是我在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

通过Thymeleaf请求的我的CSS文件也没有版本化:

<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的{​​{1}}方法似乎只是返回了所提供的资源路径,无需转换或调用ResourceUrlProvider

我目前发现的唯一解决方法是以这种方式覆盖SpringWebFluxLinkBuilder并将其设置为SpringWebFluxTemplateEngine

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

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

使用该代码,我可以对模板中调用的所有CSS / JS /图像进行版本控制。但是,我想知道这是否是必要的,或者是否只是缺少一些配置点来自动触发此逻辑。

1 个答案:

答案 0 :(得分:1)

首先,您应该删除自定义配置并依赖配置属性,因为您没有做Spring Boot已经实现的任何事情:

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

Spring URL中的资源处理支持在服务器端重写了资源URL。

首先,您应确保已启用它:

  1. 对于Spring Boot,您不应使用@EnableWebMvc@EnableWebFlux,因为它们会禁用Web自动配置
  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参考文档中可能缺少。