HttpClient多文件上传代码及普通参数中文乱码问题解决
该随笔记录了在实际项目中使用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表单 的提交方式。
客户端上传文件及普通参数代码:
/** * httpclient 文件上传 * @param postFiles * @param postUrl * @param postParam * @return */ public static Map<String, Object> uploadFileByHttpPost(File[] postFiles, String postUrl, Map<String, String> postParam) { Map<String, Object> resultMap = new HashMap<String, Object>(); CloseableHttpClient httpClient = HttpClients.createDefault(); try { //把一个普通参数和文件上传给下面这个api接口 HttpPost httpPost = new HttpPost(postUrl); //设置传输参数,设置编码。设置浏览器兼容模式,解决文件名乱码问题 MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532); for (int i = 0; i < postFiles.length; i++) { File postFile = postFiles[i]; FileBody fundFileBin = new FileBody(postFile, ContentType.MULTIPART_FORM_DATA); //相当于<input type="file" name="media"/> multipartEntity.addPart("upload_file"+i, fundFileBin); } //把文件转换成流对象FileBody Set<String> keySet = postParam.keySet(); for (String key : keySet) { //解决中文乱码 ContentType contentType = ContentType.create("text/plain", Charset.forName("UTF-8")); StringBody stringBody = new StringBody(postParam.get(key), contentType); multipartEntity.addPart(key, stringBody); // multipartEntity.addTextBody(key, postParam.get(key));//这个中文会乱码 } HttpEntity reqEntity = multipartEntity.build(); httpPost.setEntity(reqEntity); //发起请求 并返回请求的响应 CloseableHttpResponse response = httpClient.execute(httpPost); try { //打印响应状态 resultMap.put("statusCode", response.getStatusLine().getStatusCode()); //获取响应对象 HttpEntity resEntity = response.getEntity(); if (resEntity != null) { //打印响应内容 resultMap.put("data", EntityUtils.toString(resEntity, Charset.forName("UTF-8"))); } //销毁 EntityUtils.consume(resEntity); } catch (Exception e) { e.printStackTrace(); } finally { response.close(); } } catch (ClientProtocolException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally { try { httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } return resultMap; }
服务端处理请求代码
这是客户端上传的代码,我们看一下怎么接收,使用SpringMVC controller层接收文件和普通参数:
/** * 上传文件 * @throws IOException * @throws IllegalStateException */ @RequestMapping("/postFile") @ResponseBody public String postFile(HttpServletRequest request){ Map<String, Object> map = new HashMap<String, Object>(); // 创建一个通用的多部分解析器 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request .getSession().getServletContext()); String name = request.getParameter("name"); String age = request.getParameter("age"); System.out.println(name+","+age); request.getSession().getServletContext(); // 判断 request 是否有文件上传,即多部分请求 if (multipartResolver.isMultipart(request)) { // 转换成多部分request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; // 取得request中的所有文件名 Iterator<String> iter = multiRequest.getFileNames(); while (iter.hasNext()) {//多文件 // 取得上传文件 MultipartFile multipartFile = multiRequest.getFile(iter.next()); if (null != multipartFile) { // 取得当前上传文件的文件名称 String fileName = multipartFile.getOriginalFilename(); if (fileName.trim() != null && fileName.trim().length() > 0) { CommonsMultipartFile cf = (CommonsMultipartFile) multipartFile; DiskFileItem fi = (DiskFileItem) cf.getFileItem(); File tempFile = fi.getStoreLocation(); // 拿到文件,存储 try { multipartFile.transferTo(new File("F:\\static\\page\\"+multipartFile.getOriginalFilename())); } catch (IOException e) { e.printStackTrace(); return "error"; } } } } } return "success"; }
测试代码:
public static void main(String[] args) { String url = "http://localhost:8080/postFile"; File[] files = new File[2]; files[0] = new File("F:\\static\\updateFile-demo.docx"); files[1] = new File("F:\\static\\updateFile-demo02.docx"); Map<String,String> param = new HashMap<>(); param.put("name","编程大道"); param.put("age","18"); Map<String, Object> stringObjectMap = HttpClientUtil01.uploadFileByHttpPost(files, url, param); System.out.println(stringObjectMap); }
代码验证
我们上传两个文件和两个普通参数,服务端controller里的处理是,打印这两个普通参数并把两个文件保存到page目录下
启动服务
我们先启动服务端,如下图正常启动
运行测试类,控制台输出如下:
服务端输出:
查看是否保存成功
成功!!
注意事项:
但是在成功之前也遇到了问题,如下:
上传文件:
普通参数,中文乱码:
- HttpClient中转上传文件,模拟form表单提交MultipartFile文件post到服务器。解决中文乱码问题
- httpclient post 上传文件及参数包括中文乱码问题方案
- httpclient上传文件,同时带字符串参数 中文乱码问题
- HttpClient上传文件到微信素材乱码问题解决
- HttpClient PostMethod模拟带文件上传+普通字段的http请求(可解决文件为网络文件的问题)
- 解决ASIHTTP setFile上传文件后中文乱码问题
- HttpClient4.5.2版本中POST提交中文参数时乱码问题解决方法
- 使用commons-fileupload实现文件(doc、pdf)上传,提取表单参数并解决中文乱码
- 解决HttpClient的FilePart上传文件中使用中文名称文件名乱码问题
- 如何解决ASP.NET下载时的中文文件名乱码,与TXT文件中存在代码两个问题
- 解决WEB项目中文件上传中文乱码问题
- 关于HttpClient上传中文乱码的解决办法
- 解决上传文件时服务端中文文件名乱码问题
- HttpClient4.4.1 关于文件上传 中文文件名编码问题
- Content-Disposition 文件上传、下载 中文乱码 HTTP头 解决办法 Java Jersey
- 解决Http或Https中下载中文文件乱码和无法下载问题
- SpringCloud通过网关上传文件文件名中文乱码问题解决
- 解决HttpClient的FilePart上传文件中使用中文名称文件名乱码问题
- asp.net 将文件 二进制 上传 保存 再显示,解决文件流中文乱码问题。
- jsp+servlet 文件上传 解决中文乱码问题