将 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/htmltext/xmltext/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-Encodinggzip【参考方案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 结合使用的主要内容,如果未能解决你的问题,请参考以下文章

spring通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩包括AJAX)

Spring Boot 启用Gzip压缩

Linux 压缩与解压缩工具gzip/gunzip

Spring REST 控制器不处理 gzip 压缩输入

Gzip压缩与解压

Java如何在spring boot中启用gzip压缩并验证其生效