我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

现象

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

文件名乱码的代码:


private HttpEntity buildEntity(Long scenarioId, List<String> 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<NameValuePair> paramsList = new ArrayList<NameValuePair>(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<FormBodyPart> bodyPartsCopy = bodyParts != null ? new ArrayList<FormBodyPart>(bodyParts) :
                Collections.<FormBodyPart>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<FormBodyPart> parts;
    public HttpBrowserCompatibleMultipart(
            final Charset charset,
            final String boundary,
            final List<FormBodyPart> parts) {
        super(charset, boundary);
        this.parts = parts;
    }
    @Override
    public List<FormBodyPart> getBodyParts() {
        return this.parts;
    }
    
    @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<FormBodyPart> parts;
    public HttpRFC6532Multipart(
            final Charset charset,
            final String boundary,
            final List<FormBodyPart> parts) {
        super(charset, boundary);
        this.parts = parts;
    }
    @Override
    public List<FormBodyPart> 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<FormBodyPart> parts;
    public HttpStrictMultipart(
            final Charset charset,
            final String boundary,
            final List<FormBodyPart> parts) {
        super(charset, boundary);
        this.parts = parts;
    }
    @Override
    public List<FormBodyPart> 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";
    
    public static final Charset DEFAULT_CHARSET      = Consts.ASCII;
    
    public static final Charset UTF8_CHARSET         = Consts.UTF_8;
}

解决方法

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

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


private HttpEntity buildEntity(Long scenarioId, List<String> 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<String> 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();
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Zuul上传文件时中文文件名乱码怎么解决

本篇内容介绍了“Zuul上传文件时中文文件名乱码怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!问题描述在项目中又一个上传文件的oss
2023-06-19

drupal6上传中文文件名附件乱码问题解决方法

本文实例讲述了drupal6上传中文文件名附件乱码问题解决方法。分享给大家供大家参考。具体方法如下: drupal6的upload模块只能上传英文名字的文件,我经过一段时间的测试,完美解决了drupal下中文文档上传的问题。 其实文档上传,
2022-06-12

完全解决FTP上传文件名称中文乱码问题

完全解决FTP上传文件名称中文乱码问题 说明无效踩坑经历 有效解决方法定时上传文件至ftp样例 说明 今天项目上加了个定时扫描本地文件路径下所有文件实现自动上传至ftp文件服务器的功能,经测试发现一旦上传中文名称的文件
2023-08-21

文件上传到服务器文件名中文乱码问题

上传文件时文件名中文乱码的解决方法:原因:编码不一致URL编码错误文件系统限制服务器配置问题解决方案:客户端和服务器使用一致的编码(如UTF-8)正确URL编码中文汉字(如%XX)选择支持中文的文件系统(如NTFS、EXT4)配置服务器(Apache、Nginx、数据库)支持中文文件名具体步骤:客户端:使用Unicode编码(如UTF-8)和正确URL编码服务器:设置字符编码(如AddDefaultCharsetUTF-8)、使用支持Unicode的文件系统其他:使用支持中文的文件类型,避免特殊字符,考虑
文件上传到服务器文件名中文乱码问题
2024-04-02

linux中文文件名乱码怎么解决

本篇内容主要讲解“linux中文文件名乱码怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux中文文件名乱码怎么解决”吧!linux中文文件名乱码的解决办法:1、下载并安装“font
2023-06-21

java下载文件名中文乱码解决

在Java的web开发中,文件下载功能的文件名文件名乱码问题是经常遇到的。对于这个问题,不同的浏览器,解决的方法不太一样。IE的话,通过URLEncoder对filename进行UTF8编码。而其他的浏览器(firefox、chrome、safari、oper
java下载文件名中文乱码解决
2017-06-24

java文件名中文乱码解决方法

JAVA文件下载时乱码有两种情况:(推荐:java视频教程)1,下载时中文文件名乱码2,下载时因为路径中包含中文文件名乱码,提示找不到文件解决方法见下面部分代码response.setContentType("multipart/form-data");
java文件名中文乱码解决方法
2019-04-23

Python基础教程:Flask上传文件(包含中文)保存后乱码问题解决

Flask是支持文件上传的, 近来做了一个上传SQL文件的功能, SQL中会使用到中文, 泰文, 马来西亚文等多种语言, 我们通过Flask接收到文件, 先把文件保存在后端, 保存后却发现是乱码.from flask import req
2023-06-02

php上传中文数据乱码如何解决

本文小编为大家详细介绍“php上传中文数据乱码如何解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“php上传中文数据乱码如何解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。php上传中文数据乱码的解决办法:
2023-07-04

如何解决php文件中文名乱码问题

php文件中文名乱码的解决办法:1、在php文件的头部加入charset代码:2、设置“iconv('utf-8','gb2312',"upload/".$file["name"]);”即可。
2019-04-10

怎么解决php目录文件名中文乱码

这篇文章主要介绍“怎么解决php目录文件名中文乱码”,在日常操作中,相信很多人在怎么解决php目录文件名中文乱码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么解决php目录文件名中文乱码”的疑惑有所帮助!
2023-06-25

怎么解决php文件中文名乱码问题

这篇文章主要介绍了怎么解决php文件中文名乱码问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。php文件中文名乱码的解决办法:1、在php文件的头部加入charset代码:
2023-06-22

解决PHP文件名乱码的方法

解决PHP文件名乱码的方法在开发过程中,不少开发者都会遇到PHP文件名乱码的问题,特别是在处理中文文件名时。这种问题会导致文件无法正确识别和加载,给开发工作带来不便。在本文中,我们将介绍几种解决PHP文件名乱码的方法,并提供具体的代码示例
解决PHP文件名乱码的方法
2024-02-27

php中mpdf文件名乱码的解决方法

小编给大家分享一下php中mpdf文件名乱码的解决方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!php mpdf文件名乱码的解决办法:1、将“autoLang
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录