上星期用到这个MultipartEntityBuilder,调了好几天,终于调通。记录点笔记。
为什么使用这个MultipartEntityBuilder?
原业务如图下:
OA是公司的核心数据,只能内网访问。那么增加网关系统作为转发跳板,并且进行权限约束。
本来用得好好的,现在有一个新需求:外业务可以创建工作流,并可以上传附件。 原来基于httpClient form post json的方式不能支持附件。 所以增加了MultipartEntityBuilder, 用于支持附件上传。
变成类似表单提交的方式
form post
data: {...}
file...
file...
file...
使用
系统是基于maven的。引入:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.2</version> </dependency>
使用如下代码片段:
//builder MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532); builder.setCharset(Consts.UTF_8); //文本内容 StringBody contentBody = new StringBody(jsonContent,ContentType.APPLICATION_JSON); builder.addPart("data", contentBody); //文件 if(files!=null && files.size()>0){ for(File file:files){ FileBody fb = new FileBody(file, ContentType.DEFAULT_BINARY); String fileName = file.getName(); builder.addPart(fileName, fb); } } //构成总的内容 builder.setContentType(ContentType.MULTIPART_FORM_DATA); HttpEntity data = builder.build(); //提交 HttpUriRequest request = RequestBuilder.post(url.toString()).setEntity(data).build(); CloseableHttpResponse response = httpClient.execute(request);
遇到的问题
文件名乱码
网上很多代码使用的是BROWSER_COMPATIBLE。 这样子是ASICII字符,不支持中文了。需要改为使用RFC6532。
MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
响应http 411
转发的时候响应了HTTP 411。网上搜索了较多的解决方案,最终解决问题。这里需要设置几个地方。
nginx.conf 设置更大的client_max_body_size。 默认这个配置是没有内容的。
网关系统基于springMVC, MultipartHttpServletRequest请求。需要下面的方式重载一下,设置content-length
if(fileMap!=null && fileMap.size()>0){ for(String filename:fileMap.keySet()){ final MultipartFile mf = fileMap.get(filename); InputStreamBody inputStreamBody = new InputStreamBody(mf.getInputStream(), filename){ @Override public long getContentLength(){return mf.getSize();} }; builder.addPart(filename, inputStreamBody); } }
文本中文乱码
就是addPart的时候, 每个部分都有不同的content-type。
// 提交的各个部门有不同的contentType。根据contentType设置字符集。 StringBody contentBody = new StringBody(reqJson,ContentType.APPLICATION_JSON);