HttpClient使用MultipartEntityBuilder是常用的上传文件的组件,但是上传的文件名称是乱码,一直输出一堆的问号:
如何解决呢?废话少说,先直接上代码:
public static String doPostWithFiles(HttpClient httpClient, String url, Map params, Map files) throws IOException {
HttpPost method = new HttpPost(url);
ContentType contentType = ContentType.create("multipart/form-data", Charset.forName("UTF-8"));
MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532)
.setCharset(Charset.forName("UTF-8"))
.setContentType(contentType);
files.forEach((fileName, file) -> builder.addBinaryBody(fileName, file, ContentType.MULTIPART_FORM_DATA, fileName));
params.forEach((name, value) -> builder.addTextBody(name, String.valueOf(value), contentType));
method.setEntity(builder.build());
try {
HttpResponse response = httpClient.execute(method);
int sc = response.getStatusLine().getStatusCode();
if (sc != HttpServletResponse.SC_OK) {
LOG.warn("doPostWithFiles fail| statusCode=" + sc + ", params=" + params.toString());
return null;
}
return EntityUtils.toString(response.getEntity(), Consts.UTF_8);
} catch (Exception e) {
LOG.warn("PointsClient | do Post service HttpException Exception", e);
throw e;
} finally {
method.releaseConnection();
}
}
这是整个方法的完整实现,
在测试的时候参考了这里的部分内容使用HttpClient MultipartEntityBuilder 上传文件,并解决中文文件名乱码问题_12934784的技术博客_51CTO博客
但是仍然不能解决问题。
最后只能自己理解源码,来研究如何做。
比较关键的是这两行,本来params的foreach是这么写的:
files.forEach((fileName, file) -> builder.addBinaryBody(fileName, file, ContentType.MULTIPART_FORM_DATA, fileName));
params.forEach((name, value) -> builder.addTextBody(name, String.valueOf(value), ContentType.MULTIPART_FORM_DATA));
files.forEach这一行明显是上传文件的而params.forEach是用来传递参数的。问题就出在params里的中文成了乱码。
经过debug发现,经过foreach之后,builder里的参数的字符集都是Consts.ISO_8859_1,很明显这应该就是问题所在,那研究一下MULTIPART_FORM_DATA就非常必要了。我们看一下源码:
static {
APPLICATION_ATOM_XML = create("application/atom+xml", Consts.ISO_8859_1);
APPLICATION_FORM_URLENCODED = create("application/x-www-form-urlencoded", Consts.ISO_8859_1);
APPLICATION_JSON = create("application/json", Consts.UTF_8);
APPLICATION_OCTET_STREAM = create("application/octet-stream", (Charset)null);
APPLICATION_SVG_XML = create("application/svg+xml", Consts.ISO_8859_1);
APPLICATION_XHTML_XML = create("application/xhtml+xml", Consts.ISO_8859_1);
APPLICATION_XML = create("application/xml", Consts.ISO_8859_1);
MULTIPART_FORM_DATA = create("multipart/form-data", Consts.ISO_8859_1);
TEXT_HTML = create("text/html", Consts.ISO_8859_1);
TEXT_PLAIN = create("text/plain", Consts.ISO_8859_1);
TEXT_XML = create("text/xml", Consts.ISO_8859_1);
WILDCARD = create("*/*", (Charset)null);
DEFAULT_TEXT = TEXT_PLAIN;
DEFAULT_BINARY = APPLICATION_OCTET_STREAM;
}
可以看到,这里的字符集全都是Consts.ISO_8859_1,要么就没设置,因此果断直接改一下:
ContentType contentType = ContentType.create("multipart/form-data", Charset.forName("UTF-8"));
然后:
params.forEach((name, value) -> builder.addTextBody(name, String.valueOf(value), ContentType.MULTIPART_FORM_DATA));
至此,问题解决。