先看curl
curl --location --request GET 'http://127.0.0.1:8080/complaint/queryLineTeams' \
--header 'Content-Type: application/json' \
--data-raw '{
"sheetNo":"123456",
"productCodes":"2094145031"
}'
对的,你没有看错,get带请求体,长这么大,第一次看见。第一反应,这么调用接口肯定报错,没想到接口居然返回数据了。既然这样,那只能开搞了。
打开百度,搜索一番,毛也没有。然后可以自己尝试各种工具类,最终找到了hutool这个工具类,居然支持get请求带请求体。本着用就可以了,但是这个工具包太大了,想着得看看他怎么解决的。终于找到了核心代码
// 解决在Rest请求中,GET请求附带body导致GET请求被强制转换为POST
// 在sun.net.www.protocol.http.HttpURLConnection.getOutputStream0方法中,会把GET方法
// 修改为POST,而且无法调用setRequestMethod方法修改,因此此处使用反射强制修改字段属性值
// https://stackoverflow.com/questions/978061/http-get-with-request-body/983458
if(method == Method.GET && method != getMethod()){
ReflectUtil.setFieldValue(this.conn, "method", Method.GET.name());
}
看着核心代码,翻开jdk源码一看,果然自己的问题,自己自动转换了,不知道说好还是坏。只能反射搞一搞了
//HttpURLConnection
private synchronized OutputStream getOutputStream0() throws IOException {
try {
if (!this.doOutput) {
throw new ProtocolException("cannot write to a URLConnection if doOutput=false - call setDoOutput(true)");
} else {
if (this.method.equals("GET")) {
this.method = "POST"; //重点这这块
}
if ("TRACE".equals(this.method) && "http".equals(this.url.getProtocol())) {
throw new ProtocolException("HTTP method TRACE doesn't support output");
} else if (this.inputStream != null) {
throw new ProtocolException("Cannot write output after reading input.");
} else {
if (!this.checkReuseConnection()) {
this.connect();
}
boolean var1 = false;
String var8 = this.requests.findValue("Expect");
if ("100-Continue".equalsIgnoreCase(var8) && this.streaming()) {
this.http.setIgnoreContinue(false);
var1 = true;
}
if (this.streaming() && this.strOutputStream == null) {
this.writeRequests();
}
if (var1) {
this.expect100Continue();
}
this.ps = (PrintStream)this.http.getOutputStream();
if (this.streaming()) {
if (this.strOutputStream == null) {
if (this.chunkLength != -1) {
this.strOutputStream = new HttpURLConnection.StreamingOutputStream(new ChunkedOutputStream(this.ps, this.chunkLength), -1L);
} else {
long var3 = 0L;
if (this.fixedContentLengthLong != -1L) {
var3 = this.fixedContentLengthLong;
} else if (this.fixedContentLength != -1) {
var3 = (long)this.fixedContentLength;
}
this.strOutputStream = new HttpURLConnection.StreamingOutputStream(this.ps, var3);
}
}
return this.strOutputStream;
} else {
if (this.poster == null) {
this.poster = new PosterOutputStream();
}
return this.poster;
}
}
}
} catch (RuntimeException var5) {
this.disconnectInternal();
throw var5;
} catch (ProtocolException var6) {
int var2 = this.responseCode;
this.disconnectInternal();
this.responseCode = var2;
throw var6;
} catch (IOException var7) {
this.disconnectInternal();
throw var7;
}
}
把这个改成get就好了。
最后附上我东拼西凑的方法
public static String sendGetJson2(String url, String params, Map headermap) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
log.info("==sendGetson2发送的地址:"+ url);
log.info("==sendGetson2发送的请求参数:"+ JSON.toJSONString(params));
log.info("==sendGetson2头参数:"+JSON.toJSONString(headermap));
try {
//组装查询参数
String urlNameString = url;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type","application/json; charset=UTF-8");
for(Object key : headermap.keySet()){
conn.setRequestProperty(key.toString(), headermap.get(key).toString());
}
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"UTF-8"));
//将post请求转为get请求(通过反射)
// 解决在Rest请求中,GET请求附带body导致GET请求被强制转换为POST
// 在sun.net.www.protocol.http.HttpURLConnection.getOutputStream0方法中,会把GET方法
// 修改为POST,而且无法调用setRequestMethod方法修改,因此此处使用反射强制修改字段属性值
// https://stackoverflow.com/questions/978061/http-get-with-request-body/983458
List fields = new ArrayList<>() ;
Class tempClass = conn.getClass();
while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
fields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
}
for (Field field : fields) {
if ("method".equals(field.getName())){
field.setAccessible(true);
field.set(conn,"GET");
}
}
// 发送请求参数
out.print(params);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
log.info(" ==sendGetson2的result结果:"+result);
} catch (Exception e) {
log.info("==sendGetson2发送 POST 请求出现异常!"+e);
e.printStackTrace();
if(e.getMessage().length() > 500){
result = "==sendGetson2发送 POST 请求出现异常!"+ e.getMessage().substring(0,500);
} else {
result = "==sendGetson2发送 POST 请求出现异常!"+ e.getMessage();
}
}finally{//使用finally块来关闭输出流、输入流
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
log.info("==sendGetson2的请求结果:"+result);
return result;
}
其实还没完,还有一种实现,利用httpclient发包,参考我是如何!-爱代码爱编程