上星期用到這個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);