VersionResourceResolver打破CSS相对URL

时间:2015-03-05 10:27:30

标签: css spring-mvc spring-boot

我在Spring Boot 1.2.2中使用VersionResourceResolver进行缓存清除。不幸的是,它认为操纵CSS文件中指定的URI很聪明。

以Twitters Bootstrap为例。它在CSS文件所在目录上方的目录中查找字体。

@font-face {
  font-family: 'Glyphicons Halflings';

  src: url('../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}

没有VersionResourceResolver,它就像预期的那样工作:

GET http://example.com/res/css/bootstrap.min.css
GET http://example.com/res/fonts/glyphicons-halflings-regular.woff

现在我添加VersionResourceResolver:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/res/**")
            .addResourceLocations("/resources/")
            .setCachePeriod(CACHE_SECONDS)
            .resourceChain(true)
                .addResolver(new VersionResourceResolver()                      
                .addFixedVersionStrategy(buildVersion, "/**/"))
                .addResolver(new PathResourceResolver());       
}

现在发生这种情况:

GET http://example.com/res/085a8/css/bootstrap.min.css
GET http://example.com/res/085a8/css/fonts/glyphicons-halflings-regular.woff

那么,为什么会这样呢?因为有人篡改了CSS文件中的URI:

@font-face {
  font-family: 'Glyphicons Halflings';

  src: url('085a8/../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('085a8/../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('085a8/../fonts/glyphicons-halflings-regular.woff') format('woff'), url('085a8/../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}

Bootstrap就是一个例子。对于CSS资源中指定的几乎所有(奇怪的并非全部)URI都会发生这种情况。使用Spring的CssLinkResourceTransformer没有帮助。那么,我如何告诉Spring不要操纵CSS文件?

编辑:我发现,Spring调用了CssLinkResourceTransformer。但我没有在任何地方指明。可能是Spring Boot在某处自动配置。

03-05 16:12:47.711 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Transforming resource: ServletContext resource [/resources/css/bootstrap.min.css]
2015-03-05 16:12:47.716 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link modified: 77a6e2aa77283c05d58f4ab52102f55684b6fb04/../fonts/glyphicons-halflings-regular.eot (original: ../fonts/glyphicons-halflings-regular.eot)
2015-03-05 16:12:47.716 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link not modified: ../fonts/glyphicons-halflings-regular.eot?#iefix
2015-03-05 16:12:47.717 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link modified: 77a6e2aa77283c05d58f4ab52102f55684b6fb04/../fonts/glyphicons-halflings-regular.woff2 (original: ../fonts/glyphicons-halflings-regular.woff2)
2015-03-05 16:12:47.718 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link modified: 77a6e2aa77283c05d58f4ab52102f55684b6fb04/../fonts/glyphicons-halflings-regular.woff (original: ../fonts/glyphicons-halflings-regular.woff)
2015-03-05 16:12:47.719 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link modified: 77a6e2aa77283c05d58f4ab52102f55684b6fb04/../fonts/glyphicons-halflings-regular.ttf (original: ../fonts/glyphicons-halflings-regular.ttf)
2015-03-05 16:12:47.719 TRACE 11064 --- [nio-8080-exec-2] o.s.w.s.r.CssLinkResourceTransformer     : Link not modified: ../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular

Edit2:如果你注册了RessourceChain -.-,Spring会自动创建一个CssLinkResourceTransformer。见https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceChainRegistration.java#L112

2 个答案:

答案 0 :(得分:5)

Spring 4.1 +中的资源处理

您正在使用的VersionStrategy FixedVersionStrategy专为处理文件名以加载JavaScript模块的JavaScript模块加载器而定制。

由于您使用的是JavaScript模块加载程序(require.js),因此使用ContentVersionStrategy表示CSS / images和FixedVersionStrategy表示JS更适合您的应用程序。因此,将配置更改为此应修复它:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {

    VersionResourceResolver versionResolver = new VersionResourceResolver()
            .addFixedVersionStrategy(version, "/**/*.js")
            .addContentVersionStrategy(version, "/**/*.css", "/**/*.png");

    registry.addResourceHandler("/res/**")
            .addResourceLocations("/resources/")
            .setCachePeriod(CACHE_SECONDS)
            .resourceChain(true)
                .addResolver(versionResolver);
}

请注意,您不需要注册PathResourceResolverCssLinkResourceTransformer,因为它是通过检查您的配置为您完成的(您已经通过阅读源代码了解了这一点)

现在,为了更好地了解该功能,我建议您阅读this blog post并查看this example application

SPR-12669 JIRA问题

实际上,这个问题与您的用例无关,本身并不是一个错误。 Guillaume创建了WUIC project,我们正在讨论如何在Spring项目中更好地集成此资产管道。因此,作为框架开发人员,他正在为WUIC用户寻求更大的灵活性 - 资源处理功能本身正常运行。

您描述的解决方法并非旨在用于应用程序,因为您没有充分理由手动执行大量管道工作,而不是依赖于Spring的默认设置。

另外,请注意我们在这里讨论的默认值是由Spring Framework设置的,而不是由Spring Boot设置的。 Spring Boot仅仅是#34; autoconfiguring well-known locations to serve static resources

答案 1 :(得分:1)

这种行为的原因是,如果您创建ResourceChain,Spring会自动创建一个CssLinkResourceTransformer。你可以在sourcecode中看到它。这是其框架中的默认配置。

不幸的是,在我的情况下,它打破了CSS文件中的相对路径。为了避免CssLinkResourceTransformer的默认配置,您需要自己执行ResourceHandling。例如way(不推荐!)。