该随笔记录了在实际项目中使用HttpClient调用外部api,需上传文件和普通参数的代码。
笔者在使用 HttpClient 调用 http api 接口时,需要服务端上传文件和一些普通参数给 http api,如果使用 Java 自带的 HttpURLConnection 请求的话,发送 multipart/form-data + POST 请求会比较麻烦,需要设置一些边界(将文件与文件、文件与普通参数之间隔开,便于接收者截取,这是 http 协议要求的)。
因为上传文件和普通参数时,服务端读取报文是根据边界值来截取的,如果使用原生的 HttpURLConnection 则比较麻烦,所以笔者采用 HttpClient 工具,httpclient是apache 软件基金会下的子项目,它很好的封装了Http工具,面向对象的思想省去了很多细节,使程序员关注与业务逻辑处理,不用关注这些通讯细节。
笔者使用HTTPClient实现文件的上传,使用 MultipartEntityBuilder 构造请求体,实现 multipart/form-data + POST 请求http接口。下面提供了使用时的代码实现,包括服务端和客户端。
不过,笔者在使用的过程中发现,当传递的普通参数有中文时,对方接到的参数会乱码,因为开始笔者使用的是multipartEntity.addTextBody(key, postParam.get(key));的方式设置普通参数。
为了解决乱码问题,最后查到了解决办法,记录如下。
如下代码是可以上传多个文件和普通参数的,使用 multipart/form-data + POST 方式提交,模拟浏览器在页面上 form表单 的提交方式。
客户端上传文件及普通参数代码:
1 /** 2 * httpclient 文件上传 3 * @param postFiles 4 * @param postUrl 5 * @param postParam 6 * @return 7 */ 8 public static Map<String, Object> uploadFileByHttpPost(File[] postFiles, String postUrl, Map<String, String> postParam) { 9 Map<String, Object> resultMap = new HashMap<String, Object>(); 10 CloseableHttpClient httpClient = HttpClients.createDefault(); 11 try { 12 //把一个普通参数和文件上传给下面这个api接口 13 HttpPost httpPost = new HttpPost(postUrl); 14 //设置传输参数,设置编码。设置浏览器兼容模式,解决文件名乱码问题 15 MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532); 16 for (int i = 0; i < postFiles.length; i++) { 17 File postFile = postFiles[i]; 18 FileBody fundFileBin = new FileBody(postFile, ContentType.MULTIPART_FORM_DATA); 19 20 //相当于<input type="file"/> 21 multipartEntity.addPart("upload_file"+i, fundFileBin); 22 } 23 //把文件转换成流对象FileBody 24 Set<String> keySet = postParam.keySet(); 25 for (String key : keySet) { 26 //解决中文乱码 27 ContentType contentType = ContentType.create("text/plain", Charset.forName("UTF-8")); 28 StringBody stringBody = new StringBody(postParam.get(key), contentType); 29 multipartEntity.addPart(key, stringBody); 30 // multipartEntity.addTextBody(key, postParam.get(key));//这个中文会乱码 31 } 32 HttpEntity reqEntity = multipartEntity.build(); 33 httpPost.setEntity(reqEntity); 34 //发起请求 并返回请求的响应 35 CloseableHttpResponse response = httpClient.execute(httpPost); 36 try { 37 //打印响应状态 38 resultMap.put("statusCode", response.getStatusLine().getStatusCode()); 39 //获取响应对象 40 HttpEntity resEntity = response.getEntity(); 41 if (resEntity != null) { 42 //打印响应内容 43 resultMap.put("data", EntityUtils.toString(resEntity, Charset.forName("UTF-8"))); 44 } 45 //销毁 46 EntityUtils.consume(resEntity); 47 } catch (Exception e) { 48 e.printStackTrace(); 49 } finally { 50 response.close(); 51 } 52 } catch (ClientProtocolException e1) { 53 e1.printStackTrace(); 54 } catch (IOException e1) { 55 e1.printStackTrace(); 56 } finally { 57 try { 58 httpClient.close(); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 } 63 return resultMap; 64 }