在RESTful和Spring Boot / MVC / JavaConfig中使用GZIP压缩


95

我们将Spring Boot / MVC与基于注释的java-config一起用于一系列RESTful服务,并且我们希望选择性地HTTP GZIP对某些API响应启用流压缩。

我知道我可以在控制器和a中手动完成此操作byte[] @ResponseBody,但是我们更希望依靠SpringMVC基础结构(过滤器/等)并让它自动进行JSON转换和压缩(即该方法返回POJO)。

如何在ResponseBody或嵌入式Tomcat实例中启用GZIP压缩,并且以某种方式我们可以选择性地仅压缩某些响应?

谢谢!

PS .:我们目前没有任何基于XML的配置。


您应该检出GzipFilter
2014年

2
除非您知道自己在做什么,否则请勿将HTTP压缩与HTTPS一起使用
Neil McGuigan

Answers:


188

这些答案的其余部分已经过时和/或过于复杂,应该是简单的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或类似功能的代理/负载平衡器设置,因为它比Java / Tomcat的线程模型更有效,更轻松地处理静态资产和gzip MUCH。

您不想把猫扔进浴缸里,因为它忙着压缩东西而不是处理请求(或者更有可能在运行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
Andy Wilkinson

感谢您的注意。我最终放弃了这一点,因为似乎静态/动态/ tomcat / vs引导仍然是一个问题。这比应该的要难。Nginx反向代理FTW!
John Culviner

3
在SpringBoot中,新属性是server.compression.enabled = true和server.compression.mime-types = XXX,YYYgithub.com/spring
projects/

2
如果对于春季启动,我们有多个rest控制器都返回JSON响应。我们可以选择性地将zip应用于某些控制器吗?

3
您还应该提到压缩的最小响应大小(例如:10KB),否则服务器压缩每个(例如:0.5KB)请求都将成为开销。server.compression.min-response-size=10240
UsamaAmjad '19


12

这基本上与@ andy-wilkinson提供的解决方案相同,但是从Spring Boot 1.0开始,custom (...)方法具有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配置中,发现压缩似乎根本没有起作用。我正在将Spring Boot与Tomcat用作嵌入式容器,并且想知道是否需要设置除此配置之外的其他任何东西?
Michael Coxon 2014年

2
Accept-Encoding: gzip,deflate如果您使用curl,请尝试通过指定标题进行验证:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev 2014年

9

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
萨米特杰哈


6

在Tomcat中启用GZip在我的Spring Boot项目中不起作用。我使用这里找到的CompressingFilter

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}

@ user1127860 tnx可以,但是无论如何要进一步配置此过滤器?我用弹簧引导和似乎无法添加初始化参数手动在web.xml中说

5

要启用GZIP压缩,您需要修改嵌入式Tomcat实例的配置。为此,您需要EmbeddedServletContainerCustomizer在Java配置中声明一个bean,然后向其中注册一个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文档

您说要选择启用压缩。根据您的选择标准,上述方法可能就足够了。它使您可以通过请求的用户代理,响应的大小和响应的mime类型来控制压缩。

如果这不能满足您的需求,那么我相信您将必须在控制器中执行压缩并返回带有gzip内容编码标头的byte []响应。


1
将设置放在application.properties的选项的答案之间有什么区别?server.compression.enabled = true server.compression.mime-types = application / json,application / xml,text / html,text / xml,text / plain,application / javascript,text / css
lukass77

在基于属性的压缩配置可用之前就写了这个答案。它们是等效的,但是基于属性的方法更容易,所以我建议使用它。
安迪·威尔金森

我只是想分享一下,在我的情况下,tomcat位于负载均衡器的后面,该负载均衡器获取https并将formcat的请求转发为http。当我使用application.properties解决方案时,响应不是gzip,但是当我在连接器上使用编程配置解决方案时,我得到了使用https请求LB的gzip响应LB
lukass77

如果我使用application.properties解决方案..并在8081和8082端口上定义更多2个连接器,则另一个问题..压缩是否适用于所有连接器或仅适用于8080连接器?
lukass77

我证实这一点,即使您打开更多的连接器,也只能在端口8080上使用..我认为应该在此上打开bug才能进行弹簧引导?? ..,所以对我来说,唯一的解决方案是为每个连接器进行编程配置,不是application.properties
lukass77

0

调用时,我在Spring Boot + Spring Data项目中遇到了相同的问题@RepositoryRestResource

问题是返回的MIME类型。这是application/hal+json。将其添加到server.compression.mime-types属性中为我解决了这个问题。

希望这对其他人有帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.