将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 RESTful 结合使用
Posted
技术标签:
【中文标题】将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 RESTful 结合使用【英文标题】:Using GZIP compression with Spring Boot/MVC/JavaConfig with RESTful 【发布时间】:2014-02-20 00:43:45 【问题描述】:我们将 Spring Boot/MVC 与基于注解的 java-config 一起用于一系列 RESTful 服务,并且我们希望对某些 API 响应选择性地启用 HTTP GZIP 流压缩。
我知道我可以在我的控制器和byte[] @ResponseBody
中手动执行此操作,但是我们更愿意依赖 Spring MVC 基础架构(过滤器/等)并让它自动执行 JSON 转换和压缩(即方法返回一个 POJO)。
如何在 ResponseBody 或嵌入式 Tomcat 实例中启用 GZIP 压缩,并且我们可以选择性地仅压缩某些响应?
我们目前没有任何基于 XML 的配置。
【问题讨论】:
你应该看看GzipFilter。 除非您知道自己在做什么,否则不要将 HTTP 压缩与 HTTPS 一起使用 【参考方案1】:这些答案的其余部分已经过时和/或对于应该是简单的 IMO 的东西来说过于复杂了(gzip 现在存在多长时间了?比 Java 还长......)来自文档:
在 application.properties 1.3+
# ?️?️?️
server.compression.enabled=true
# opt in to content types
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
# not worth the CPU cycles at some point, probably
server.compression.min-response-size=10240
在 application.properties 1.2.2 - <1.3
server.tomcat.compression=on
server.tomcat.compressableMimeTypes=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
早于 1.2.2:
@Component
public class TomcatCustomizer implements TomcatConnectorCustomizer
@Override
public void customize(Connector connector)
connector.setProperty("compression", "on");
// Add json and xml mime types, as they're not in the mimetype list by default
connector.setProperty("compressableMimeType", "text/html,text/xml,text/plain,application/json,application/xml");
另请注意,这仅在您运行嵌入式 tomcat 时才有效:
如果您计划部署到非嵌入式 tomcat,则必须在 server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation 中启用它
IRL 制作说明:
为了避免所有这些,请考虑在 Tomcat 前面使用代理/负载均衡器设置,并带有 nginx 和/或 haproxy 或类似的,因为它将处理静态资产和gzip 比 Java/Tomcat 的线程模型更高效、更容易。
您不想将 'cat 扔进浴缸,因为它忙于压缩内容而不是提供请求(或者更有可能在运行 AWS 时启动线程/占用 CPU/堆等待数据库 IO 发生)这就是为什么传统的 Java/Tomcat 可能不是一个好主意的原因,这取决于你在做什么,但我离题了......)
参考: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#how-to-enable-http-response-compression
https://github.com/spring-projects/spring-boot/issues/2031
【讨论】:
您对 1.2.2 之前版本的方法将不起作用,因为 Spring Boot 不会在应用程序上下文中查找TomcatConnectorCustomizer
实例;他们必须以编程方式注册TomcatEmbeddedServletContainerFactory
感谢您的提醒。我最终放弃了这一点,因为静态/动态/tomcat/vs boot 似乎仍然是一个问题。这比它应该做的要难...... nginx 反向代理 FTW!
在 SpringBoot 中,新的属性是 server.compression.enabled=true 和 server.compression.mime-types=XXX,YYY github.com/spring-projects/spring-boot/wiki/…
如果对于 Spring Boot,我们有多个 rest 控制器都返回 JSON 响应。我们可以选择性地在某些控制器上应用 zip 吗?
您还应该提及压缩的最小响应大小(例如:10KB),否则服务器压缩每个请求(例如:0.5KB)会成为开销。 server.compression.min-response-size=10240
【参考方案2】:
application.yml
配置中的最新版本:
---
spring:
profiles: dev
server:
compression:
enabled: true
mime-types: text/html,text/css,application/javascript,application/json
---
【讨论】:
相应的错误报告和修复是github.com/spring-projects/spring-boot/issues/2737 可以使用通配符 mime 类型吗?即image/*
?它似乎不起作用【参考方案3】:
这与@andy-wilkinson 提供的解决方案基本相同,但从 Spring Boot 1.0 开始,customize(...) 方法有一个ConfigurableEmbeddedServletContainer 参数。
另外值得一提的是,Tomcat默认只压缩text/html
、text/xml
和text/plain
的内容类型。下面是一个同样支持application/json
压缩的例子:
@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer()
return new EmbeddedServletContainerCustomizer()
@Override
public void customize(ConfigurableEmbeddedServletContainer servletContainer)
((TomcatEmbeddedServletContainerFactory) servletContainer).addConnectorCustomizers(
new TomcatConnectorCustomizer()
@Override
public void customize(Connector connector)
AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
httpProtocol.setCompression("on");
httpProtocol.setCompressionMinSize(256);
String mimeTypes = httpProtocol.getCompressableMimeTypes();
String mimeTypesWithJson = mimeTypes + "," + MediaType.APPLICATION_JSON_VALUE;
httpProtocol.setCompressableMimeTypes(mimeTypesWithJson);
);
;
【讨论】:
我尝试将其添加到我的 Java 配置中,发现压缩似乎根本没有运行。我正在使用带有 Tomcat 的 Spring Boot 作为嵌入式容器,想知道除了这个配置之外我还需要设置什么其他的东西吗? 尝试通过指定Accept-Encoding: gzip,deflate
标头进行验证,如果您使用 curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
【参考方案4】:
Spring Boot 1.4 将此用于 Javascript HTML Json 所有压缩。
server.compression.enabled: true
server.compression.mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
【讨论】:
我们如何验证这种压缩? @Bhargav 查看您的 api 响应的响应标头。它应该包含标题:Content-Encoding
:gzip
【参考方案5】:
我为此添加了:
服务器压缩
server.compression.enabled=true
server.compression.min-response-size=2048
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
取自http://bisaga.com/blog/programming/web-compression-on-spring-boot-application/
【讨论】:
【参考方案6】:在 Tomcat 中启用 GZip 在我的 Spring Boot 项目中不起作用。我用CompressingFilter发现here。
@Bean
public Filter compressingFilter()
CompressingFilter compressingFilter = new CompressingFilter();
return compressingFilter;
【讨论】:
@user1127860 tnx 这可行,但无论如何要进一步配置此过滤器?我使用 spring boot 并且似乎无法像 web.xml 中所说的那样添加初始化参数【参考方案7】:要启用 GZIP 压缩,您需要修改嵌入式 Tomcat 实例的配置。为此,您需要在 Java 配置中声明一个 EmbeddedServletContainerCustomizer
bean,然后向它注册一个 TomcatConnectorCustomizer
。
例如:
@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer()
return new EmbeddedServletContainerCustomizer()
@Override
public void customize(ConfigurableEmbeddedServletContainerFactory factory)
((TomcatEmbeddedServletContainerFactory) factory).addConnectorCustomizers(new TomcatConnectorCustomizer()
@Override
public void customize(Connector connector)
AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
httpProtocol.setCompression("on");
httpProtocol.setCompressionMinSize(64);
);
;
有关可用的各种压缩配置选项的更多详细信息,请参阅Tomcat documentation。
您说您想有选择地启用压缩。根据您的选择标准,上述方法可能就足够了。它使您能够通过请求的用户代理、响应的大小和响应的 mime 类型来控制压缩。
如果这不能满足您的需求,那么我相信您将不得不在控制器中执行压缩并返回带有 gzip 内容编码标头的 byte[] 响应。
【讨论】:
您对将设置放在 application.properties 上的选项的回答有什么不同? server.compression.enabled=true server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css 这个答案是在基于属性的压缩配置可用之前编写的。它们是等价的,但是基于属性的方法更容易,所以我建议使用它。 只是想分享一下,在我的情况下,tomcat 位于负载均衡器后面,该负载均衡器获取 https 并将对 tomcat 的请求转发为 http .,当我使用 application.properties 解决方案时,响应不是 gzip,而是当我使用连接器上的编程配置解决方案我通过 https 请求 LB 得到 gzip 响应 另一个问题,如果我使用 application.properties 解决方案 .. 并在 8081 和 8082 端口上定义更多 2 个连接器 .. 压缩适用于所有连接器还是仅适用于 8080 连接器? 我验证了这一点,压缩仅适用于端口 8080,即使您打开更多连接器..,我认为错误应该在此打开到 spring boot ??..,所以只有工作解决方案我是每个连接器的编程配置,而不是 application.properties【参考方案8】:在调用@RepositoryRestResource
时,我的 Spring Boot+Spring Data 项目遇到了同样的问题。
问题是返回的 MIME 类型;这是application/hal+json
。将它添加到 server.compression.mime-types
属性为我解决了这个问题。
希望这对其他人有帮助!
【讨论】:
以上是关于将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 RESTful 结合使用的主要内容,如果未能解决你的问题,请参考以下文章