遇到一种业务场景,前端上传的文件需要经过java服务转发至文件服务。期间遇到了原生HttpClient怎么使用的问题、怎么把MultipartFile怎么重新组装成Http请求发送出去的问题、文件中文名乱码问题。最后都解决了,先上代码,再讲遇到的坑

  1. @Slf4j
  2. @Service
  3. public class FileServiceImpl implements IFileService {
  4.  
  5. @Value("${FileService.putUrl}")
  6. private String putUrl;
  7. @Value("${FileService.app_id}")
  8. private String appId;
  9. @Value("${FileService.securityKey}")
  10. private String secureKey;
  11.  
  12. private final static String UPLOAD_RESPONSE_CODE = "error";
  13. private final static Integer UPLOAD_RESPONSE_SUCCESS = 0;
  14.  
  15. @Override
  16. public String upload(MultipartFile file) {
  17.  
  18. int timeOut = 30000;
  19. CloseableHttpClient httpClient = HttpClientBuilder.create().build();
  20. HttpHost proxy = new HttpHost("127.0.0.1", 62145, "http"); //设置本地fiddler代理,方便排查问题
  21. RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
  22. .setConnectTimeout(timeOut).setSocketTimeout(timeOut).setProxy(proxy).build();
  23. HttpPost httpPost = new HttpPost(putUrl);
  24. httpPost.setConfig(requestConfig);
  25. try {
  26. //BROWSER_COMPATIBLE自定义charset,RFC6532=utf-8,STRICT=iso-8859-1
  27. //此处一定要用RFC6532,网上普遍用的BROWSER_COMPATIBLE依然会出现中文名乱码
  28. MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
  29. //multipartEntityBuilder.setCharset(Charset.forName("UTF-8")); //此处踩坑,转发出去的filename依然为乱码
  30. //ContentType contentType = ContentType.create("multipart/form-data",Charset.forName("UTF-8")); //此处也是坑,转发出去的filename依然为乱码
  31. multipartEntityBuilder.addBinaryBody("file", file.getInputStream(), ContentType.DEFAULT_BINARY, file.getOriginalFilename());
  32.  
  33. multipartEntityBuilder.addTextBody("app_id", appId); //可替换成你自己需要的附加字段
  34. long time = System.currentTimeMillis() / 1000;
  35. multipartEntityBuilder.addTextBody("time", String.valueOf(time)); //可替换成你自己需要的附加字段
  36. String beforeSign = String.format("app_id=%s&time=%s%s", appId, time, secureKey);
  37. String sign = MD5Util.md5(beforeSign);
  38. multipartEntityBuilder.addTextBody("sign", sign); //可替换成你自己需要的附加字段
  39.  
  40. HttpEntity requestEntity = multipartEntityBuilder.build();
  41. httpPost.setEntity(requestEntity);
  42. HttpResponse httpResponse = httpClient.execute(httpPost);
  43. int statusCode= httpResponse.getStatusLine().getStatusCode();
  44. if (statusCode != 200) throw new BizException(BizCode.INNER_SERVICE_ERROR, "响应状态码为:" + statusCode);
  45. HttpEntity responseEntity = httpResponse.getEntity();
  46. return getUrlString(EntityUtils.toString(responseEntity));
  47. } catch (Exception e) {
  48. log.error("发送文件异常:{}", e);
  49. throw new BizException(BizCode.INNER_SERVICE_ERROR, "发送文件服务异常:" + e.getMessage());
  50. } finally {
  51. try {
  52. httpClient.close();
  53. } catch (IOException e) {
  54. log.error("关闭httpClient异常:" + e.getMessage(), e);
  55. }
  56. }
  57. }
  58.  
  59. private String getUrlString(String jsonString) {
  60. try{
  61. log.debug("解析json串:"+ jsonString);
  62. JSONObject jsonObject = JSONObject.parseObject(jsonString);
  63. if (jsonObject.getInteger(UPLOAD_RESPONSE_CODE) != UPLOAD_RESPONSE_SUCCESS) {
  64. log.error("文件服务返回错误:" + jsonObject.getString("data"));
  65. throw new OtherServiceReturnErrorException("文件服务返回错误:" + jsonObject.getString("data"));
  66. }
  67. return ((JSONObject)jsonObject.get("data")).get("original").toString();
  68. }catch (Exception e) {
  69. log.error("文件服务返回json解析错误:" + jsonString);
  70. throw new OtherServiceReturnErrorException("文件服务返回json解析错误:" + jsonString);
  71. }
  72.  
  73. }
  74. }

特别说明及遇到的坑:

1. 这里基于tomcat进行请求转发,需要在代码中手动添加代理:

  1. HttpHost proxy = new HttpHost("127.0.0.1", 62145, "http"); //设置本地fiddler代理,方便排查问题
    RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
    .setConnectTimeout(timeOut).setSocketTimeout(timeOut).setProxy(proxy).build();

2. MultipartFile通过getInputStream()可以将流设置到MultipartEntityBuilder中,其中addBinaryBody里面的ContentType 和 filename必须设置,要不然后续服务读取不到这个文件流

MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
multipartEntityBuilder.addBinaryBody("file", file.getInputStream(), ContentType.DEFAULT_BINARY, file.getOriginalFilename());

3. file.getOriginalFilename()方法虽然没有乱码,但是addBinaryBody后,组装的Http请求出去总是乱码,如下图:

踩了各种坑,如为MultipartEntityBuilder设置Charset或者是手动设置ContentType,都无法解决此问题,文件名依然是上图所示乱码

后来发现在MultipartEntityBuilder中设置Mode为HttpMultipartMode.RFC6532可以完美解决这个问题,并且不再需要单独设置ContentType或Charset,因为HttpMultipartMode.RFC6532就告诉了MultipartEntityBuilder,里面的数据都要使用UTF-8进行处理,fiddler抓到的请求发现filename成功变成中文名。

done

  1.  

使用HttpClient MultipartEntityBuilder 上传文件,并解决中文文件名乱码问题的更多相关文章

  1. CuteFTP 9.0 上传文件时,中文文件名乱码

    解决办法如图: 1.右键--->属性 2.选项---->档案名称编  选择ascⅡ

  2. HttpClient MultipartEntityBuilder 上传文件

    文章转载自: http://blog.csdn.net/yan8024/article/details/46531901 http://www.51testing.com/html/56/n-3707 ...

  3. dotnetcore下解压zip文件,解决中文文件名乱码问题

    (迄今为止网上那些说的用Encoding.Default解决中文文件名乱码的都不能真正解决问题!) 1.在程序开始处 Encoding.RegisterProvider(CodePagesEncodi ...

  4. python向ftp上传文件,解决中文问题

    # coding: UTF-8 import os import sys import salt.client import salt.config import time from ftplib i ...

  5. 转 Android网络编程之使用HttpClient批量上传文件 MultipartEntityBuilder

    请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件 http://www.tuicool.com/articles/Y7reYb 我曾在<Andr ...

  6. Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件(二)

    Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件第二版 上次粗略的写了相同功能的代码,这次整理修复了之前的一些BUG,结构也大量修改 ...

  7. Chrome不能在网易网盘中上传文件的解决办法

    Chrome不能在网易网盘中上传文件的解决办法1. 安装 Adobe Flash Player PPAPI,设置flash插件 chrome://settings/content/flash,许可[* ...

  8. C# 应用 - 使用 HttpClient 发起上传文件、下载文件请求

    1. 示例代码 using System; using System.IO; using System.Net.Http; /// <summary> /// 下载文件 /// </ ...

  9. 利用struts2上传文件时,如果文件名中含有-符号,那么会出错

    利用struts2上传文件时,如果文件名中含有-符号,那么会出错 报错如下: HTTP Status 500 - C:\Program Files\Apache Software Foundation ...

随机推荐

  1. 78-DeMarker,价格波动指数.(2015.7.1)

    DeMarker 价格波动指数 观井映天 2015.7.1

  2. Huawei-R&S-网络工程师实验笔记20190615-IP基础(AR201上配置IP)

    >Huawei-R&S-网络工程师实验笔记20190615-IP基础(AR201上配置IP) >>实验开始,先上拓扑图参考: >>>一般正常配置IP操作如下 ...

  3. Thawte 企业版代码签名证书

      Thawte企业版代码签名证书 ,严格验证企业身份,如果您是个人开放者,请申请Thawte 个人代码签名证书.Thawte企业代码签名证书 可帮助程序开发者使用微软代码签名工具(Microsoft ...

  4. 添物零基础到架构师(基础篇) - JavaScript

    JavaScript是什么? JavaScript是web开发必须学习的,ECMAScript是其规则来源. JavaScript的历史 Developed by Brendan Eich of Ne ...

  5. ZOJ 1298_Domino Effect

    题意: 多米诺骨牌效应:若干个关键牌相连,关键牌之间含有普通牌,关键牌倒下后其所在的行的普通牌全部倒下.求从推倒1号关键牌开始,最终倒下的牌的位置及时间. 分析: 最终倒下的牌的位置有两种情况,要么是 ...

  6. HDU——2063 过山车

    过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  7. mysql性能调优——Query优化

    上节谈了关于mysql锁定机制的优化方案,下面来谈一下Query优化——Mysql Query Optimizer 当Mysql Query Optimizer接受到从Query Parser过来的Q ...

  8. Errors running builder 'JavaScript Validator' on

    eclipse编译提示Errors running builder 'JavaScript Validator' on 解决方法见下图 去掉 'JavaScript Validator' 即可

  9. sql 按中文排序

    sql server:select * from [表名]order by [字段],[字段] collate Chinese_PRC_CS_AS_KS_WS mysql:select * from ...

  10. mybatis返回list很智能很简答的,只需要配置resultmap进行类型转换,你dao方法直接写返回值list<对应的object>就行了啊

    mybatis返回list很智能很简答的,只需要配置resultmap进行类型转换,你dao方法直接写返回值list<对应的object>就行了啊 dao方法 public List< ...