问题:
最近需要通过Post请求通过表单形式(Content-Type:multipart/form-data)传递文本数据,但是调用其他服务接口的时候,使用PostMan调用一切正常,但是使用Java代码的httpclient包的HttpPost请求该接口时报错:
{"timestamp":1681893336914,"status":500,"error":"Internal Server Error","exception":"org.springframework.web.multipart.MultipartException","message":"Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found","path":"/xxx"}
从字面意思来看是找不到分隔符“boundary”而报错了。
分析:
通过抓包来看,postman请求的时候会自动在Content-Type后面并接一个随机生成的boundary(“boundary= xxxxx”),然后再对请求体进行一个分隔符包装。
- 截图:
-
请求头Conten—type:
-
请求体文本:
-
postman自动生成“boundary”的地方
-
要解决这个问题就要解决:
如何使用HttpPost请求自动生成“boundary”放到请求头Conten-Type并用该“boundary”包装请求体呢?
解决:
核心代码:
HttpPost httpPost = new HttpPost(url);
//boundary分隔符随机生成
String boundary = UUIDGenerator.generateUUIDWithOutSlash();
//【核心】这里boundary=别忘了!!!!!!!
httpPost.addHeader(HTTP.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
log.info("请求 openapi Authorization:{}", headerAuth);
MultipartEntityBuilder builder = MultipartEntityBuilder.create()
//【核心】这里别忘了设置!!!!
.setBoundary(boundary);
if (!CollectionUtils.isEmpty(param)) {
//设置请求体参数
for (String item : param.keySet()) {
//添加文本类容,如果要发送文件就使用 builder.addBinaryBody
builder.addTextBody(item,param.get(item));
}
}
//构建请求实体
HttpEntity entity = builder.build();
httpPost.setEntity(entity);
CloseableHttpResponse response = httpClient.execute(httpPost);
MultipartEntityBuilder这个类如果无法引入请引入如下jar包,版本号和httpclient保持一致即可:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>