У нас есть веб-приложение Spring Boot с Thymeleaf. В шаблонах HTML мы ссылаемся на некоторые ресурсы * stati c, например /src/main/resources/static/js/main.js
через <script defer th:src="@{/js/main.js}"></script>
.
Чтобы позволить браузерам кэшировать ресурсы stati c для нескольких посещений нашего веб-сайта, мы включить управление версиями контента:
spring.resources:
chain:
strategy.content:
enabled: true
paths: /**
cache.cachecontrol.max-age: 365d
Все это отлично работает, и мы получаем ресурс с его MD5 га sh, добавленным к имени файла (например, /main-d9f17fd70ee583fef4acf26dd331b8ab.js
).
Для дальнейшего уменьшения трафика c том, теперь мы хотим включить сжатие ресурсов с помощью 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 и обнаружили следующее:
org.springframework.web.servlet.resource.VersionResourceResolver#getResponseHeaders
всегда устанавливает (сильный) заголовок ETag:
public HttpHeaders getResponseHeaders() {
HttpHeaders headers = (this.original instanceof HttpResource ?
((HttpResource) this.original).getResponseHeaders() : new HttpHeaders());
headers.setETag("\"" + this.version + "\"");
return headers;
}
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 .. .
Чтобы продемонстрировать проблему, я создал пример проекта в Github с тремя проходными тестами и одним провальным тестом, который показывает, где наши ожидания не оправдываются ...
У вас есть идея, как решить это противоречие? Мы что-то делаем неправильно?