带有ContentVersionStrategy的Spring Boot缓存禁止使用gzip压缩资源

问题描述 投票:0回答:1

我们有一个Thymeleaf的Spring Boot Web应用程序。在HTML模板内部,我们引用了一些静态资源,例如/src/main/resources/static/js/main.js通过<script defer th:src="@{/js/main.js}"></script>

为了允许浏览器为访问我们的网站多次而缓存静态资源,我们启用内容版本控制:

spring.resources:
    chain:
      strategy.content:
        enabled: true
        paths: /**
    cache.cachecontrol.max-age: 365d

这一切都很好,我们得到的资源的MD5哈希值附加到文件名(例如/main-d9f17fd70ee583fef4acf26dd331b8ab.js)。

为了进一步减少流量,我们现在要使用gzip启用资源压缩:

server:
  compression:
    enabled: true
    mime-types: application/javascript,and-some-others
    min-response-size: 1024

当请求标头为Accept-Encoding='gzip'的(版本化的)资源时,我们没有获得带有Content-Encoding='gzip'的响应。因此,资源压缩似乎无法与内容版本控制一起使用。

如果禁用内容版本控制,资源压缩就可以正常工作:为(现在是非版本化的)资源设置了Content-Encoding='gzip'标头。

因此,我们深入研究了Spring的内部,发现了以下内容:

  1. [org.springframework.web.servlet.resource.VersionResourceResolver#getResponseHeaders始终设置(strong)ETag标头:
public HttpHeaders getResponseHeaders() {
    HttpHeaders headers = (this.original instanceof HttpResource ?
            ((HttpResource) this.original).getResponseHeaders() : new HttpHeaders());
    headers.setETag("\"" + this.version + "\"");
    return headers;
}
  1. org.apache.coyote.CompressionConfig#useCompression禁用压缩,如果存在强大的ETag:
public boolean useCompression(Request request, Response response) {
    ...
    if (noCompressionStrongETag) {
        String eTag = responseHeaders.getHeader("ETag");
        if (eTag != null && !eTag.trim().startsWith("W/")) {
            // Has an ETag that doesn't start with "W/..." so it must be a
            // strong ETag
            return false;
        }
    }
    ...
}

您可以将noCompressionStrongETag设置为false,但是不建议使用,它将在Tomcat 10中删除...

为了演示该问题,我创建了一个example project in Github,其中包含3个通过测试和1个失败测试,​​这些测试表明无法满足我们的期望...

您有解决该矛盾的想法吗?我们在做严重错误的事情吗?

java spring-boot gzip etag
1个回答
0
投票

现在在Spring's Github repository中跟踪了该问题。当前的想法是在Spring的VersionResourceResolver中从强ETag切换到弱ETag。问题解决后,我将更新此答案。

© www.soinside.com 2019 - 2024. All rights reserved.