java - 无法使用 Spring Webflux 和 Thymeleaf 对静态资源进行版本控制
问题描述
我尝试使用 Spring Webflux 在我的应用程序上实现静态内容版本控制,如文档中所述:https ://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux -配置静态资源
我有以下使用版本资源解析器的资源处理程序:
@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/”中,并在 URL 中添加“test_version”。
但是,在请求的所有资源中,只有少数请求是使用 URL 中的版本完成的。
例如,以下是请求图像的示例:
这是请求的唯一一个在 URL 中添加版本的图像:
我的 JS 或 CSS 资源没有两个版本。我没有看到版本化资源和非版本化资源之间的 HTTP 级别(标头等)有任何差异,与 ETag 标头不同。
这是我的项目配置:Spring Boot 2.1.0.RELEASE 和 Spring Webflux、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}">
但是,通过 CSS 请求的图像具有良好的版本:
.test {
background: url('/images/versioned.png');
}
我通过 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
似乎通过 a 解析资源路径SpringWebFluxLinkBuilder
,其processLink
方法似乎只是返回提供的资源路径,没有转换或调用ResourceUrlProvider
.
我目前发现的唯一解决方法是覆盖SpringWebFluxLinkBuilder
这种方式并将其设置为SpringWebFluxTemplateEngine
:
@Override
public String processLink(IExpressionContext context, String link) {
return super.processLink(context, "test_version" + link);
}
使用该代码,我可以对模板中调用的所有 CSS/JS/图像进行版本控制。但是,我想知道这是否有必要,或者我是否只是缺少一些配置点来自动触发此逻辑。
解决方案
首先,您应该放弃自定义配置并依赖配置属性,因为您没有做任何 Spring Boot 已经实现的事情:
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.version=test_version
资源 URL 在服务器端由 Spring Framework 中的资源处理支持重写。
首先,您应该确保它已启用:
- 在 Spring Boot 的情况下,您不应该使用
@EnableWebMvc
or@EnableWebFlux
,因为它们会禁用 Web 自动配置 - 资源链接应该在模板文件中或由 Spring 重写的文件中(例如 CSS 文件)
- 资源 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 参考文档中可能缺少某些内容。
推荐阅读
- google-cloud-platform - SSH 到专用网络中的 VM 不起作用
- c# - 硒窗口不关闭
- x86-64 - x86_64 架构是否在不断更新?
- javascript - Firestore 数据库不会出现
- api - 在 QGIS 'Hqgis' 插件中使用 HERE API 循环路由。可以做到吗?
- woocommerce - 仅针对特定条款在函数内运行税务查询(WooCommerce)
- delphi - 是否可以对属性使用相同的 getter 和 setter?
- outlook - 从 Outlook 主题行中提取文本
- sql - SQL 根据 ParentID 和 Child ID 对数据进行分组
- xslt - 在一个查询中使用 sum 翻译函数