SpringBoot 启用 GZIP 对响应进行压缩
SpringBoot Web 应用默认是不启用响应数据的压缩,对大的文本类型的响应数据进行压缩是十分必要的,如 JSON, XML 等应用数据,甚至是 JS, CSS 等。早先的 Web 应用基本是要配置一个叫做GzipFilter之类的东西,然后判断请求的是否含有gzip, 再对需要的响应类型的数据进行压缩。在使用了 SpringBoot 之后,在碰到有压缩响应的需求的时候,第一件事情应该要想到
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 , 介绍了三个配置项
- server.compression.enable=true (默认为 false, 不启用压缩)
- server.compression.min-response-size=2048 (默认至少 2K 字节以及以上大小的响应数据才被压缩, 要在网络带宽与 CPU 消耗上找到一个平衡)
- 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); }
@ 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
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
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); }
@ 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); }
@ 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
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"); } }
@ 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 ......
AddOutputFilterByType DEFLATE text / plain AddOutputFilterByType DEFLATE text / html . . . . . . |
逐项加入要支持压缩的响应类型
具体使用方式请参照 Apache Module mod_deflate 的文档。
更多推荐
所有评论(0)