目录
- 一、背景
- 二、排查过程
- 三、解决方法
- 四、学习与思考-响应压缩
- (一)可能原因
- (二)深入排查
- (三)注意
一、背景
接口发布到测试环境,测试同学说没有数据
二、排查过程
1、本地用相同的参数、相同的库、相同的代码分支,发现接口正常且有响应数据
2、怀疑是不是运维配置操作导致不是一个数据库
3、排查所有可能用到的测试库以及分支,发现接口还是正常的
4、实际去测试环境看接口请求响应,发现接口是200通的,但是response是空的,说明没有响应体
5、测试环境:请求接口对应的sprinboot项目服务是通过nginx转发的
最终怀疑是响应nginx拦截了
三、解决方法
- springboot项目的yml配置文件如下
server:
port: 55129
servlet:
context-path: /test
compression:
mime-types: application/json
enabled: true
- 这里的true改为false,问题解决了
四、学习与思考-响应压缩
(一)可能原因
- 客户端不支持压缩:客户端(像浏览器或者其他调用接口的应用程序)可能不支持服务器所采用的压缩格式(通常是 gzip 或者
deflate)。当客户端接收到压缩后的响应体时,无法正确对其进行解压缩,从而造成无法解析响应数据。 - 代理服务器问题:Nginx 作为代理服务器,可能没有正确处理压缩响应。例如,在转发响应时,Nginx
可能移除了与压缩相关的请求头或者响应头,使得客户端无法识别响应是经过压缩的,进而无法正确解析。 - 压缩配置错误:Spring Boot
的压缩配置可能存在错误,比如压缩算法不兼容、压缩级别设置不合理等,导致压缩后的响应体无法被客户端正确解析。
(二)深入排查
1、检查客户端请求头:要确保客户端在请求头中包含 Accept-Encoding 字段,并且其值为 gzip, deflate,以此表明客户端支持这些压缩格式。例如,在使用 HttpClient 发送请求时,可以这样设置请求头:
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpClientExample {
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://your_domain_or_ip/bi/your_endpoint"))
.header("Accept-Encoding", "gzip, deflate")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
2、配置 Nginx 支持压缩:在 Nginx 配置文件中添加压缩相关的配置,确保 Nginx 能够正确处理压缩响应。示例配置如下:
server {
listen 80;
server_name your_domain_or_ip;
gzip on;
gzip_types application/json text/html text/css application/javascript;
location /bi {
proxy_pass http://localhost:55129/bi;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Accept-Encoding ""; # 移除客户端的Accept-Encoding头
proxy_pass_header Content-Encoding; # 传递响应的Content-Encoding头
}
}
3、检查 Spring Boot 压缩配置:确保 Spring Boot 的压缩配置正确,例如 mime-types 设置是否包含了你希望压缩的响应类型。
server:
port: 55129
servlet:
context-path: /test
compression:
mime-types: application/json, text/html, text/css, application/javascript
enabled: true
4、与后端服务器压缩配置冲突:如果后端服务器(如 Spring Boot 应用)配置了响应压缩,而 Nginx 没有相应配置,可能会出现一些问题。例如,Nginx 可能会在转发响应时移除或修改与压缩相关的请求头和响应头,导致客户端无法正确识别和处理压缩后的数据。
移除或修改请求头
后端服务器在收到客户端请求时,会检查请求头中的Accept-Encoding字段,以确定客户端支持的压缩算法。如果客户端支持gzip或deflate等压缩算法,后端服务器会对响应数据进行压缩,并在响应头中添加Content-Encoding字段,告知客户端响应数据的压缩方式。
然而,Nginx
在转发请求时,如果没有配置处理压缩相关的请求头,可能会默认移除Accept-Encoding请求头。这样,后端服务器就无法得知客户端支持的压缩算法,可能会导致后端服务器对原本可以压缩的数据不进行压缩,或者采用客户端不支持的压缩算法进行压缩。
移除或修改响应头
后端服务器将压缩后的响应数据发送给 Nginx,Nginx
在转发响应时,如果没有配置处理压缩相关的响应头,可能会移除Content-Encoding响应头。客户端接收响应时,由于没有Content-Encoding头信息,无法得知响应数据是经过压缩的,会按照未压缩的数据格式进行解析,导致解析错误。
另外,Nginx
也可能会修改Content-Length响应头。因为压缩后的数据长度通常会小于原始数据长度,后端服务器会根据压缩后的数据长度设置Content-Length头。但
Nginx
如果不了解压缩情况,可能会错误地修改Content-Length头为原始数据长度,导致客户端在读取响应数据时,按照错误的长度进行读取,从而出现数据不完整或解析错误的情况。
- 我们项目实际上就是nginx没有配置响应压缩,而springboot项目配置了响应压缩,导致接口没有响应体。
(三)注意
当前把 enabled 设为 false 虽然解决了问题,但这样会使响应压缩功能失效,在传输大文件或者大量数据时,会增加网络带宽的占用,降低数据传输的速度。