前言
我们知道一般无论是 CDN 还是 服务端的接口(nginx 配置gzip以优化站点资源加载速度),在响应返回的时候,都会配置 gzip 来压缩响应数据,以达到减少体积,加快网络传输的效能。 但是 gzip 压缩只用于 response 的响应数据,一般来说针对 pc 端的站点来说,足够了。
但是有时候针对手机 app 来说,光是 response 用 gzip 压缩还不够, 因为 request 请求的时候,如果有时候 body 体带上很多数据的话,还是会导致体积很大,从而消耗流量。 手机的流量可比 pc 的流量贵多了。 因此对于有些比较注重流量消耗的 app 来说,最好也要做到 request 请求的时候,也用上 gzip 来压缩数据,然后服务端在 nginx 或者程序的网关那边,再根据请求头 Content-Encoding
是否为 gzip
来判断是否要对请求的数据进行 gzip 解压缩。
实操
接下来我将通过用 golang 语言来模拟客户端的请求和服务端的响应是否要带上 gzip 头部,来模拟这一过程,代码很简单,而且已经极简了,客户端代码就是 client.go
, 服务端代码就是 server.go
, 不需要用到第三方库。 (我的 golang 环境是 1.13.8
)
客户端
client.go
:
1 | package main |
可以看到,我这边通过 flag 来控制本次请求中, request 是否要 gzip 压缩,要求 response 是否也要 gzip 压缩返回。 所以总共有以下四种可能:
- request gzip 压缩, response gzip 压缩
- request gzip 压缩, response 不 压缩
- request 不 压缩, response gzip 压缩
- request 不 压缩, response 不 压缩
服务端
server.go
:
1 | package main |
运行起来
首先先运行服务端:
1 | go run server.go |
接下来针对以上 4 种情况,分别运行 客户端 程序,然后查看一下服务端的输出
1. 都压缩
客户端指令:
1 | ~ >go run client.go |
服务端输出:
1 | resquest content length= 85 |
2. request 压缩, response 不压缩
客户端指令:
1 | ~ >go run client.go -resp_use_gzip=0 -req_use_gzip=1 |
服务端输出:
1 | resquest content length= 85 |
3. request 不压缩, response 压缩
客户端指令:
1 | ~ >go run client.go -resp_use_gzip=1 -req_use_gzip=0 |
服务端输出:
1 | resquest content length= 64 |
4. 都不压缩
客户端指令:
1 | ~ >go run client.go -resp_use_gzip=0 -req_use_gzip=0 |
服务端输出:
1 | resquest content length= 64 |
其实判断是否要用 gzip 压缩很简单,通过 request 或者 response 的头部设置即可:
- 如果自身设置
Content-Encoding
为gzip
, 说明你的数据是 gzip 压缩过的, 对方要进行 gzip 解压才行 - 如果你希望对方给你的数据是 gzip 压缩过的,那么就设置头部
Accept-Encoding
为gzip
gzip 压缩后体积更大的情况
不知道以上有一种情况,你们有没有发现过,就是无论是 request 还是 response 的数据, gzip 压缩过后的字节体积比原先更多了,反而是不压缩的字节体积更小,为了更直观,我列个表格:
- | 请求 body 字节 | 响应 body 字节 |
---|---|---|
都压缩 | 85 | 50 |
只压缩 request | 85 | 26 |
只压缩 response | 64 | 50 |
都不压缩 | 64 | 26 |
其实这样子是对的,事实上 gzip 压缩的时候,在原数据比较小的时候,反而压缩后的体积会更大, 这也是为啥 nginx 要有一个 gzip_min_length
参数来控制压缩的最小字节数,一般我们是设置为 1k (默认值是 20), 具体可以看 gzip 配置 gzip_min_length 来判断 response 是否要 gzip 压缩
接下来我们将 请求的 body 和 响应的 body 都调大一点
1 | respJson := []byte(`{code: "1",msg: "success", des: "12asdfsafsafsagaegewgsdfsdfsdfsdfgghhhhhhhhhhsfgegrfsdffffffffffadffwefwefefwafrrrrrrrrrrrrrwgsdfsdfsdfsdfgghhhhhhhhhhsfgegrfsdffffffffffadffwefwefefwafrrrrrrrrrwgsdfsdfsdfsdfgghhhhhhhhhhsfgegrfsdffffffffffadffwefwefefwafrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"}`) |
1 | var requestBodyStr = `{"name":"zach ke","des":"woooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boywoooooo boy", "response_use_gzip": "%s"}` |
可以看到 都压缩后的体积是:
1 | request with gzip |
1 | resquest content length= 89 |
分别是请求体积是 89, 响应体积 111。
而如果是没有压缩的,那么就是:
1 | request without gzip |
1 | resquest content length= 383 |
分别是请求体积是 383, 响应体积 343。 可以看到这个压缩率就不错了。
总结
基本上数据量越多的话, 用 gzip 能省的流量越多,而且还能够加快网络传输,何乐而不为。 (事实上,还可以设置压缩比例和压缩算法,我这边为了演示,只使用默认的配置)
不过request 请求的话,如果用 gzip 的话,会影响性能的,数据量越大的话, 压缩和解压所消耗的时间也会越长,所以一般 pc 端的站点也不需要, 只有一些对流量消耗比较敏感的 app 可以考虑用这种方式。