使用HttpClient MultipartEntityBuilder 上传文件,并解决中文文件名乱码问题

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

特别说明及遇到的坑:

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

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



原文地址:https://www.cnblogs.com/evasean/p/9368670.html

时间: 2024-08-02 18:54:03

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

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

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

httpclient 4.3 psot方法上传文件与参数 中文乱码解决

废话不多说,直接上有码的! 1 package httpclient; 2 3 import java.io.File; 4 import java.nio.charset.Charset; 5 6 import org.apache.http.Consts; 7 import org.apache.http.Header; 8 import org.apache.http.HttpEntity; 9 import org.apache.http.client.methods.Closeable

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

请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件 http://www.tuicool.com/articles/Y7reYb 我曾在<Android网络编程之使用HTTP访问网络资源>一文中介绍过HttpCient的使用,这里就不在累述了,感兴趣的朋友可以去看一下.在这里主要介绍如何通过HttpClient实现文件上传. 1.预备知识: 在HttpCient4.3之前上传文件主要使用MultipartEntity这个类,但现在这个类已经不在推

Android网络编程之使用HttpClient批量上传文件

请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件 我曾在<Android网络编程之使用HTTP访问网络资源>一文中介绍过HttpCient的使用,这里就不在累述了,感兴趣的朋友可以去看一下.在这里主要介绍如何通过HttpClient实现文件上传. 1.预备知识: 在HttpCient4.3之前上传文件主要使用MultipartEntity这个类,但现在这个类已经不在推荐使用了.随之替代它的类是MultipartEntityBuilder. 下面

Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听

请尊重他人的劳动成果,转载请注明出处: Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听 运行效果图: 我曾在<Android网络编程之使用HttpClient批量上传文件>一文中介绍过如何通过HttpClient实现多文件上传和服务器的接收.在上一篇主要使用Handler+HttpClient的方式实现文件上传.这一篇将介绍使用AsyncTask+HttpClient实现文件上传并监听上传进度. 监控进度实现: 首先

PHP文件上传并解决中文文件名乱码问题

PHP文件上传并解决中文文件名乱码问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 if(isset($_FILES['file'])){ ? ????$upload='upload/'.$_FILES['file']['name']; ????? ????? ????if(is_uploaded_file($_FILES['file']['tmp_name'])){ ????????//iconv函数解决上传文件中文名乱码的问题,但是不提倡文

fileUpload上传文件,并设置文件名以及保存服务器位置

我做的是上传Excel文件,保存内容到数据库. 下面部分代码是fileUpload上传文件,并设置文件名以及保存服务器位置. if (fileUpload.HasFile) { string fileNameNo = Path.GetFileName(fileUpload.PostedFile.FileName); //获取文件名和扩展名 fileNameNo = fileNameNo.Replace("(", "-").Replace(")",

Struts2 .apk 文件下载及解决中文文件名乱码问题(转)

1.Tomcat服务器不能下载 .apk类型文件 Android的APK安装包不能下载或下载文件是以 .zip为后缀名而不是 .apk为文件后缀名时,需在 Tomcat 的 web.xml 配置文件中加入以下 MIME 类型: 1 <mime-mapping> 2 <extension>apk</extension> 3 <mime-type>application/vnd.android.package-archive</mime-type>

Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件

折腾了好几天的 HTTP 终于搞定了,经测试正常,不过是初步用例测试用的,因为后面还要修改先把当前版本保存在博客里吧. 其中POST因为涉及多段上传需要导入两个包文件,我用的是最新的 httpmine4.3 发现网上很多 MultipartEntity 相关的文章都是早起版本的,以前的一些方法虽然还可用,但新版本中已经不建议使用了,所以全部使用新的方式 MultipartEntityBuilder 来处理了. httpmime-4.3.2.jar httpcore-4.3.1.jar 下载地址: