【问题标题】:Using GZIP compression with Spring Boot/MVC/JavaConfig with RESTful将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 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 一起使用

标签: java spring rest spring-mvc gzip


【解决方案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

---

【讨论】:

【解决方案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 属性为我解决了这个问题。

    希望这对其他人有帮助!

    【讨论】:

      猜你喜欢
      • 2016-06-13
      • 2015-07-14
      • 1970-01-01
      • 2015-09-19
      • 1970-01-01
      • 2017-02-01
      • 1970-01-01
      • 2022-11-30
      相关资源
      最近更新 更多