微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

基于HttpClient上传文件中文名乱码的解决

这篇文章主要介绍了HttpClient上传文件中文名乱码的解决方案,具有很好的参考价值,希望对大家有所帮助。

现象

使用HttpClient工具上传文件时,如果文件名是中文文件名会乱码

文件名乱码的代码

private httpentity buildEntity(Long scenarioId, List groupIds, String extension,File filetoUpload) { multipartentityBuilder builder = multipartentityBuilder.create(); builder.addTextBody("scenarioId", scenarioId.toString()); for (String groupId : groupIds) { builder.addTextBody("groupIds", groupId); } builder.addTextBody("extension", extension); builder.addPart("filetoUpload", new FileBody(filetoUpload)); builder.addTextBody("type", AssetFileTypeEnum.CSV.getName()); builder.addTextBody("issplit", "false"); builder.addTextBody("isRefresh", "false"); return builder.build();

乱码原因:

HttpClient上传文件时,会调用doWriteto方法,写一个输出流,但是在调用formatMultipartHeader方法时,底层主要有3种不同的实现,3种方式的采用的字符集不一样

HttpClient中的doWriteto方法

void doWriteto( final OutputStream out, final boolean writeContent) throws IOException { final ByteArrayBuffer boundaryEncoded = encode(this.charset, this.boundary); for (final FormBodyPart part: getBodyParts()) { writeBytes(TWO_DASHES, out); writeBytes(boundaryEncoded, out); writeBytes(CR_LF, out); //此处代码主要有3种不同的实现,不同的mode,实现方式不一样,采用的字符集也不同 formatMultipartHeader(part, out); writeBytes(CR_LF, out); if (writeContent) { part.getBody().writeto(out); } writeBytes(CR_LF, out); } writeBytes(TWO_DASHES, out); writeBytes(boundaryEncoded, out); writeBytes(TWO_DASHES, out); writeBytes(CR_LF, out); }

其中的formatMultipartHeader方法,不同的模式有不同的实现方式

multipartentityBuilder

MultipartFormEntity buildEntity() { String boundarycopy = boundary; if (boundarycopy == null && contentType != null) { boundarycopy = contentType.getParameter("boundary"); } if (boundarycopy == null) { boundarycopy = generateBoundary(); } Charset charsetcopy = charset; if (charsetcopy == null && contentType != null) { charsetcopy = contentType.getCharset(); } final List paramsList = new ArrayList(2); paramsList.add(new BasicNameValuePair("boundary", boundarycopy)); if (charsetcopy != null) { paramsList.add(new BasicNameValuePair("charset", charsetcopy.name())); } final NameValuePair[] params = paramsList.toArray(new NameValuePair[paramsList.size()]); final ContentType contentTypecopy = contentType != null ? contentType.withParameters(params) : ContentType.create("multipart/" + DEFAULT_SUBTYPE, params); final List bodyPartscopy = bodyParts != null ? new ArrayList(bodyParts) : Collections.emptyList(); //此处将mode赋值给modecopy final HttpMultipartMode modecopy = mode != null ? mode : HttpMultipartMode.STRICT; final AbstractMultipartForm form; //此处根据modecopy的值不同,构造3种form,每种的字符集都不一样,也是产生乱码的根源 switch (modecopy) { case broWSER_COMPATIBLE: form = new HttpbrowserCompatibleMultipart(charsetcopy, boundarycopy, bodyPartscopy); break; case RFC6532: form = new HttpRFC6532Multipart(charsetcopy, boundarycopy, bodyPartscopy); break; default: form = new HttpStrictMultipart(charsetcopy, boundarycopy, bodyPartscopy); } return new MultipartFormEntity(form, contentTypecopy, form.getTotalLength()); } public httpentity build() { return buildEntity(); }

broWSER_COMPATIBLE模式中的formatMultipartHeader方法

class HttpbrowserCompatibleMultipart extends AbstractMultipartForm { private final List parts; public HttpbrowserCompatibleMultipart( final Charset charset, final String boundary, final List parts) { super(charset, boundary); this.parts = parts; } @Override public List getBodyParts() { return this.parts; } /** * Write the multipart header fields; depends on the style. */ @Override protected void formatMultipartHeader( final FormBodyPart part, final OutputStream out) throws IOException { // For browser-compatible, only write Content-disposition // Use content charset final Header header = part.getHeader(); final MinimalField cd = header.getField(MIME.CONTENT_disPOSITION); //可以看到此处的字符集采用的是设置的字符集 writeField(cd, this.charset, out); final String filename = part.getBody().getFilename(); if (filename != null) { final MinimalField ct = header.getField(MIME.CONTENT_TYPE); //可以看到此处的字符集采用的也是设置的字符集 writeField(ct, this.charset, out); } } }

RFC6532模式中的formatMultipartHeader方法

class HttpRFC6532Multipart extends AbstractMultipartForm { private final List parts; public HttpRFC6532Multipart( final Charset charset, final String boundary, final List parts) { super(charset, boundary); this.parts = parts; } @Override public List getBodyParts() { return this.parts; } @Override protected void formatMultipartHeader( final FormBodyPart part, final OutputStream out) throws IOException { // For RFC6532, we output all fields with UTF-8 encoding. final Header header = part.getHeader(); for (final MinimalField field: header) { //可以看到此处的字符集认采用UTF8 writeField(field, MIME.UTF8_CHARSET, out); } } }

认模式中的formatMultipartHeader方法

class HttpStrictMultipart extends AbstractMultipartForm { private final List parts; public HttpStrictMultipart( final Charset charset, final String boundary, final List parts) { super(charset, boundary); this.parts = parts; } @Override public List getBodyParts() { return this.parts; } @Override protected void formatMultipartHeader( final FormBodyPart part, final OutputStream out) throws IOException { // For strict, we output all fields with MIME-standard encoding. //从上面注释中可以看到,此处的字符集采用的是认字符集即ASCII(下面MIME类中可以看到) final Header header = part.getHeader(); for (final MinimalField field: header) { writeField(field, out); } } }

MIME类

public final class MIME { public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TRANSFER_ENC = "Content-transfer-encoding"; public static final String CONTENT_disPOSITION = "Content-disposition"; public static final String ENC_8BIT = "8bit"; public static final String ENC_BINARY = "binary"; /** The default character set to be used, i.e. "US-ASCII" */ public static final Charset DEFAULT_CHARSET = Consts.ASCII; /** UTF-8 is used for RFC6532 */ public static final Charset UTF8_CHARSET = Consts.UTF_8; }

解决方法

知道乱码产生的根源,乱码问题也就好解决了,解决方式有两种

设置mode为:broWSER_COMPATIBLE,并设置字符集为UTF8

private httpentity buildEntity(Long scenarioId, List groupIds, String extension, File filetoUpload) { multipartentityBuilder builder = multipartentityBuilder.create(); //设置模式为broWSER_COMPATIBLE,并设置字符集为UTF8 builder.setMode(HttpMultipartMode.broWSER_COMPATIBLE); builder.setCharset(Charset.forName("UTF-8")); builder.addTextBody("scenarioId", scenarioId.toString()); for (String groupId : groupIds) { builder.addTextBody("groupIds", groupId); } builder.addTextBody("extension", extension); builder.addPart("filetoUpload", new FileBody(filetoUpload)); builder.addTextBody("type", AssetFileTypeEnum.CSV.getName()); builder.addTextBody("issplit", "false"); builder.addTextBody("isRefresh", "false"); return builder.build(); }

设置模式为:RFC6532

private httpentity buildEntity(Long scenarioId, List groupIds, String extension, File filetoUpload) { multipartentityBuilder builder = multipartentityBuilder.create(); //设置模式为RFC6532 builder.setMode(HttpMultipartMode.RFC6532); builder.addTextBody("scenarioId", scenarioId.toString()); for (String groupId : groupIds) { builder.addTextBody("groupIds", groupId); } builder.addTextBody("extension", extension); builder.addPart("filetoUpload", new FileBody(filetoUpload)); builder.addTextBody("type", AssetFileTypeEnum.CSV.getName()); builder.addTextBody("issplit", "false"); builder.addTextBody("isRefresh", "false"); return builder.build(); }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐