2

SpringBoot 启用 GZIP 对响应进行压缩

 2 years ago
source link: https://yanbin.blog/springboot-enable-gzip-respone-compression/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

SpringBoot 启用 GZIP 对响应进行压缩

2022-08-30 |

SpringBoot Web 应用默认是不启用响应数据的压缩,对大的文本类型的响应数据进行压缩是十分必要的,如 JSON, XML 等应用数据,甚至是 JS, CSS 等。

早先的 Web 应用基本是要配置一个叫做 GzipFilter 之类的东西,然后判断请求的 Accept-Encoding 是否含有 gzip, 再对需要的 Content-Type 响应类型的数据进行压缩。

在使用了 SpringBoot 之后,在碰到有压缩响应的需求的时候,第一件事情应该要想到是否能通过在 application.properties(或 application.yml) 配置就行。于是查阅 SpringBoot 2.7.x 的帮助文档 Spring Boot Reference Document, 搜索关键字 compression,翻几页就能找到 17.3.6. Enable HTTP Response Compression, 介绍了三个配置项

  1. server.compression.enable=true            (默认为 false, 不启用压缩)
  2. server.compression.min-response-size=2048  (默认至少 2K 字节以及以上大小的响应数据才被压缩, 要在网络带宽与 CPU 消耗上找到一个平衡)
  3. server.compression.mim-types=text/html,text/xml,text/plain,text/css,text/javascript,application/json,application/xml (默认压缩的响应类型)

再往下找到 .A.11.Server Properties, 还有一个相关的选项

  • server.compression.exclude-user-agents=  (默认为空,逗号分隔的 user-agent, 针对什么 user-agent 不启用压缩,可能给测试用的)

如果是 SpringBoot 1.2.x 的话,启用压缩的方法是不一样的,详情同样是参考官方的文档 64.18 Enable HTTP response compression

这里我们再回到当前的 SpringBoot 2.7.x 版本,其实只要是 SpringBoot 1.3+ 的版本,唯一要做的就是配置

server.compression.enable=true

其他三个选项根据基本满足我们的日常要求了,或者按需稍加调节。

下面进行一些实战烟训,默认未配置 server.compression.enable 时,即默认为 false, 不启用响应压缩,写一个 controller 方法

@GetMapping(value = "/hello")
public String hello(@RequestParam int length) {
    return StringUtils.repeat("0", length);

curl 测试

bash-3.2$ curl -I http://localhost:8080/hello?length=2047
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2047
Date: Tue, 30 Aug 2022 03:01:53 GMT
bash-3.2$ curl -I http://localhost:8080/hello?length=2048
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2048
Date: Tue, 30 Aug 2022 03:01:56 GMT
bash-3.2$ curl -I -H "Accept-Encoding:gzip" http://localhost:8080/hello?length=2049
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2049
Date: Tue, 30 Aug 2022 03:02:20 GMT

怎么都不会对响应进行压缩,现在我们在 application.properties 中加上

server.compression.enabled = true

bash-3.2$ curl -I -H "Accept-Encoding:gzip" http://localhost:8080/hello?length=2047
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2047
Date: Tue, 30 Aug 2022 13:22:14 GMT
bash-3.2$ curl -I http://localhost:8080/hello?length=2048
HTTP/1.1 200
vary: accept-encoding
Content-Type: text/plain;charset=UTF-8
Content-Length: 2048
Date: Tue, 30 Aug 2022 13:22:16 GMT
bash-3.2$ curl -I -H "Accept-Encoding:gzip" http://localhost:8080/hello?length=2048
HTTP/1.1 200
vary: accept-encoding
Content-Encoding: gzip
Content-Type: text/plain;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 30 Aug 2022 13:22:18 GMT

响应长度为 2048 及以上会采用压缩,并且这时不管有没有 Accept-Encoding:gzip 都会加上 vary: accept-encoding 用以区分不同的响应数据,像 Varnish 就要考虑 Accept-Encoding 作为 Key 的一部分缓存是否压缩的数据。

关于 server.compression.mime-types

前面提过它的默认值是 text/html,text/xml,text/plain,text/css,text/javascript,application/json,application/xml, 即只对这些 Content-Type 类型的数据进行压缩,不该压缩的类型注意不要重复压缩,如 image/jpg, application/octet-stream 等.

text/plain 对 Content-Type:text/plain;charset=UTF-8 同样是适用的

不支持通配符配置,如不能用 text/* 来涵盖所有以 text/ 开头的类型,像 test/html, test/xml, text/plain 等。必须一个个罗列出来

server.compression.mime-types 中的配置是区分大小写的,如

server.compression.mime-types=TEXT/PLAIN

对 Content-Type:text/plain 是不启作用的

bash-3.2$ curl -I -H "Accept-Encoding:gzip" http://localhost:8080/hello?length=2049
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 2049
Date: Tue, 30 Aug 2022 14:20:21 GMT

如果我们把 API 的 Content-Type 也设置为 TEXT/PLAIN 就能被压缩了

@GetMapping(value = "/hello")
public ResponseEntity<String> hello(HttpServletResponse response, @RequestParam int length) {
    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Content-Type", "TEXT/PLAIN");
    return new ResponseEntity<>(StringUtils.repeat("0", length), headers,  HttpStatus.OK);

bash-3.2$ curl -I -H "Accept-Encoding:gzip" http://localhost:8080/hello?length=2049
HTTP/1.1 200
vary: accept-encoding
Content-Encoding: gzip
Content-Type: TEXT/PLAIN
Transfer-Encoding: chunked
Date: Tue, 30 Aug 2022 14:22:20 GMT

注意在 Spring Web controller 方法中,对于标准的 Content-Type 是无法通过 @GetMapping 注解的 produces 和 HttpServletResponse 来改变的

@GetMapping(value = "/hello", produces = "TEXT/PLAIN")
public String hello(HttpServletResponse response, @RequestParam int length) {
    response.setHeader("Content-Type", "TEXT/PLAIN");
    return StringUtils.repeat("0", length);

以上代码最终的 Content-Type 仍然为 text/plain;charset=UTF-8

其他相关的内容

SpringBoot 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

SpringBoot 1.2.2 之前,在使用 Tomcat 作为内嵌应用服务器时,通过  TomcatConnectorCustomizer

@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 本身可配置 server.xml 中的 connector 自动实现对响应数据的压缩,在 Apache Tomcat 10 Configuration Reference - The HTTP Connector 一章中查找 compression 就能找到下面这几个属性

  • compression: off|on|force (默认为 off)
  • compressibleMimeType: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml
  • compressionMinSize: 2048
  • noCompressionUserAgents: 默认为空,可使用正则表达式

HTTP/2 connector 也继承了以上几个属性配置

Apache HTTP Server 的压缩模块

如果部署时在应用服务器(如  Tomcat) 前端配置了 Apache HTTP Server 的话,可以由 Apache 完成对数据的压缩,要使用到的模块是 mod_defalte

比如在 Debian 系的 OS 中 a2enmod deflate, 或在 httpd.conf 中用 LoadModule deflate_module modules/mod_deflate.so 启用。然后在 http.conf 或是应用的 .htaccess 文件中

AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
......

逐项加入要支持压缩的响应类型

具体使用方式请参照 Apache Module mod_deflate 的文档。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK