前言
本问题主要是来自于同事
情况大致如下, 同样的代码 一个是测试用例, 一个是生产环境的应用, 访问同一个第三方服务, 参数什么的完全一致
但是 出现的问题就是 测试用例能够拿到正确的对方的响应, 但是 生产环境的应用 却是拿到的对方的报错
然后 我开始以为是 是否是 签名数据存在问题, 但是 使用 curl 将两套请求[测试用例/生产环境的应用] 发送给对方服务器, 是能够拿到正确的响应的
所以 所有的参数 什么的都是正常的, 那么可能存在的差异的地方就是 两套发包的 jar 是否一致, 验证一下 是相同的
另外 就是 http 客户端 是否存在问题, 然后 检查了一下 测试用例 的客户端 和 生产应用的客户端, 测试用例的是 hutool-all-5.8.6, 生产应用的是 hutool-all-5.4.0
然后 二话不说 在开发机上面写了一个 case 来发送请求到对方服务器
然后 使用不同的 hutool-all 的包, 然后 果然 问题复现了
然后 之后抓包看了一下 两个版本发送的请求, 原来 是 hutool-5.4.0 将我的 get 请求改成了 post 请求, 然后 导致对方服务响应异常
这里 大概是根据 实际的问题情况 复现一下 这一整套情况
测试用例
代码使用如下相同的代码, 测试的时候 切换 hutool-all 的依赖的版本
package com.hx.test05;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Test16PostHutoolRequest
*
* @author Jerry.X.He
* @version 1.0
* @date 2023/2/19 15:22
*/
public class Test16PostHutoolRequest {
// Test16PostHutoolRequest
public static void main(String[] args) {
String url = "http://localhost:8291/userHome/serviceStats";
HttpRequest request = HttpUtil.createRequest(Method.GET, url);
Map<String, String> params = new LinkedHashMap<>();
params.put("pageNo", "1");
request.body(JSON.toJSONString(params));
Map<String, String> headers = new LinkedHashMap<>();
headers.put("Content-Type", "application/json;charset=UTF-8");
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36");
headers.put("Accept", "application/json, text/plain, */*");
request.addHeaders(headers);
HttpResponse response = request.execute();
System.out.println(response.body());
int x = 0;
}
}
服务端代码大致如下
主要的处理就是针对 “/serviceStats” 的 get, post 做出不同的处理, 以方便观察
@Operation(summary = "服务统计查询")
@GetMapping("/serviceStats")
@ResponseStatus(HttpStatus.OK)
public ResponseData<JSONObject> serviceStats() {
JSONObject result = new JSONObject();
result.put("availableServiceCount", 5);
result.put("unavailableServiceCount", 5);
return super.ok(result);
}
@Operation(summary = "服务统计查询")
@PostMapping("/serviceStats")
@ResponseStatus(HttpStatus.OK)
public ResponseData<UserHomeServiceStatusView> serviceStats2() {
throw new RuntimeException("服务器异常");
}
在高版本的 hutool-all 5.7.4 请求的结果如下
在 hutool-all 5.4.0 请求的结果如下, 可以看到的是 发送的 GET 请求, 走的是 POST 的处理
问题抓包分析
在 hutool-all-5.7.4 版本中抓包 发送的请求如下, 发现 代码中发送的 GET 请求, 实际上发的包是 GET请求
在 hutool-all-5.4.0 版本中抓包 发送的请求如下, 发现 代码中发送的 GET 请求, 实际上发的包是 POST 请求
问题代码分析
将 get 换成 post 的地方居然是在 jdk 的 HttpUrlConnection 里面
只要是使用了 HttpUrlConnection.getOutputStream 的 get 请求, 都会被换成 post 请求
HttpConnection.getOutputStream 的处理方式如下, 直接 获取 HttpURLConnection 的 outputStream
然后我们来看一下 hutool-5.7.4 中的处理方式
这里对 这里场景做了 特殊的处理
这个问题的修复在 5.4.2 版本中修复的
Change Log 参见 CHANGELOG_5.0-5.7
具体的调整来自于这里 commitLog
完