最近在开发过程中,遇到了我们公司的几个老项目,采用的是传统单体项目,这种项目之间需要交互,项目A请求项目B,B将结果回调给A,我们采用了Http Post请求的方式,在接收Http请求的时候,遇到了不少问题,所以总结一下接收Http Post请求的几种方式。
请求类型必须是:application/json
/**
* 主动请求方-A
*/
@PostMapping("request-callback")
public static void requestCallback() {
TreeMap<String, String> map = new TreeMap<>();
map.put("name", "六六");
map.put("age", "2");
map.put("version", "1.0");
String response;
try {
response = RequestUtil.post("http://127.0.0.1:8080/callback/response-callback", map);
} catch (Exception e) {
throw new RuntimeException("请求异常!");
}
LOGGER.info("回调返回 response = :{}", response);
}
// 项目A日志结果:回调返回 response = :回调成功!
/**
* 接收请求方-B-1
*/
@PostMapping("response-callback")
public String responseCallback(@RequestBody CallbackDTO callbackDTO) {
if (callbackDTO != null) {
LOGGER.info("dto:{}", JSON.toJSONString(callbackDTO));
return "回调成功!";
}
return "回调失败!";
}
// 项目B日志结果:dto:{"age":2,"name":"六六","version":"1.0"}
比如,前端提交一个表单:
<input type="text" name="p_name" value="六六">
<input type="text" name="p_age" value="2">
<input type="text" name="f_sex" value="女">
request.getParameterMap()会得到一个Map:
{
p_name=六六, p_age=2, f_sex=女}
但是我们后端可能只需要带"p_"这个前缀的字段,这时我们就可以用WebUtils.getParametersStartingWith(request, “p_”)这个方法去指定获取带"p_"前缀的字段,返回值也是一个Map。它会去掉前缀并且将不是"p_"前缀的字段过滤掉:
{
name=六六, age=2}
也可以不传参,WebUtils.getParametersStartingWith(request, “”),他获取的结果和request.getParameterMap()一样:
{
p_name=六六, p_age=2, f_sex=女}
/**
* 主动请求方-A
*/
@PostMapping("request-callback")
public static void requestCallback() {
TreeMap<String, String> map = new TreeMap<>();
map.put("p_name", "六六");
map.put("p_age", "2");
map.put("f_version", "1.0");
String response;
try {
response = RequestUtil.post("http://127.0.0.1:8080/callback/response-callback", map);
} catch (Exception e) {
throw new RuntimeException("请求异常!");
}
LOGGER.info("回调返回 response = :{}", response);
}
// 项目A日志结果:回调返回 response = :回调成功!
/**
* 接收请求方-B-2
*/
@PostMapping("response-callback")
public String responseCallback() {
Map<String, Object> params = WebUtils.getParametersStartingWith(request, "p_");
LOGGER.info("params :{}", JSON.toJSONString(params));
return "回调成功!";
}
// 项目B日志结果:params :{"age":"2","name":"六六"}
和我们预想的一样,项目B接收到了请求,获取到了"p_"前缀的参数,将前缀自动去掉,并且给了项目B回调结果。
/**
* 主动请求方-A
*/
@PostMapping("request-callback")
public static void requestCallback() {
TreeMap<String, String> map = new TreeMap<>();
map.put("name", "六六");
map.put("age", "2");
map.put("version", "1.0");
String response;
try {
response = RequestUtil.post("http://127.0.0.1:8080/callback/response-callback", map);
} catch (Exception e) {
throw new RuntimeException("请求异常!");
}
LOGGER.info("回调返回 response = :{}", response);
}
// 项目A日志结果:回调返回 response = :回调成功!
/**
* 接收请求方-B-3
*/
@PostMapping("response-callback")
public String responseCallback() {
String content;
try {
StringBuilder sb = new StringBuilder();
String line;
while (!StringUtils.isBlank((line = request.getReader().readLine()))) {
sb.append(line);
}
content = sb.toString();
LOGGER.info("content = {}", content);
} catch (Exception e) {
LOGGER.error("msg={},stack={}", e.getMessage(), ExceptionUtils.getStackTrace(e));
}
return "回调成功!";
}
// 项目B日志结果:content = {"age":"2","name":"六六","version":"1.0"}
使用request.getInputStream()返回请求内容字节流一样可以获取。
我使用的Http请求工具类有两个,一个是hutool工具类,一个自己封装的。
<!--hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.1.8</version>
</dependency>
/**
* fshows.com
* Copyright (C) 2013-2019 All Rights Reserved.
*/
package com.example.callbackdemo.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* post请求工具类
* @author liuyuan
*/
@Slf4j
public class RequestUtils {
/**
* 超时时间10秒
*/
private static final int TIMEOUT = 10000;
public static String post(String url, Object object) {
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(TIMEOUT).setConnectTimeout(TIMEOUT).build();
String content = null;
HttpPost post = new HttpPost(url);
post.addHeader("Content-Type", "application/json");
post.setConfig(requestConfig);
String body = JSON.toJSONString(object, SerializerFeature.WriteNullStringAsEmpty);
log.info("执行POST请求 body={}", body);
post.setEntity(new StringEntity(body, "UTF-8"));
try {
CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse closeableHttpResponse = client.execute(post);
content = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
} catch (IOException e) {
log.warn("执行POST请求异常params={},e={}", JSON.toJSONString(object), ExceptionUtils.getStackTrace(e));
} finally {
post.releaseConnection();
}
return content;
}
}
request.getParameter()、request.getInputStream()、request.getReader()和@RequestBody注解是互斥的,只能调用其中一个,如果想要同时使用,需要做特殊处理。