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

解决中文上传乱码
本文详细介绍了在上传中文文件名时遇到的乱码问题及四种解决方案:修改Tomcat配置、逆向编码解码、设置POST请求编码及通过web.xml配置。每种方法优缺点并茂,便于开发者选择。

遇到了一个问题,在开发时上传文件时,文件的中文名上传的是中文乱码,所解决方法:

文章转载自:https://blog.youkuaiyun.com/lengjinghk/article/details/51938644

一、对Tomcat_HOME/conf/server.xml文件进行配置(本机的完整目录为D:/Users/Administrator/Tomcat/apache-tomcat-7.0.54/conf/server.xml)
核心代码如下(其中最后一句是自己加的):

  1. <Connector executor="tomcatThreadPool"

  2.         port="8080" protocol="HTTP/1.1"

  3.         connectionTimeout="20000"

  4.         redirectPort="8443"

  5.         URIEncoding="utf-8" />

         或者 URIEncoding="GBK"

这种方式一般不建议使用,因为它修改的是Tomcat平台的编码,而业内没人对其不修改,如果人为修改会影响其他项目的运行。


二、逆向编码解码还原法
之所以会出现乱码,是因为浏览器将中文传给tomcat时,tomcat以默认的iso8859-1方式对其解码,而iso8859-1不属于中文码表,故而出现乱码。根据这个原理可逆向还原。
如:

 
  1. byte buf[] = request.getParameter("name").getBytes("iso8859-1");

  2. String name = new String(buf,"GBK");

这样得到的name便是前台传来的正确的中文参数了
这种方式比较偏向底层,而且有一个弊端,就是当浏览器传送的中文参数很多时,需要一个个设置,比较罗嗦,不利于节省时间。


三、将浏览器的表单的提交方式设为post方式,同时在servlet里在接受参数前将request的编码设置为GBK或者UTF-8。
前端形如:

  1. <form action="login.jsp" method="post">

  2.     用户名:<input type="text" name="name"><br/><br/>

  3.     密    码:<input type="text" name="pwd"><br/><br/>

  4.     <input type="submit" value="登录">

  5. </form>

后端形如:

  1. request.setCharacterEncoding("utf-8");

  2. String name = request.getParameter("name");

这样也能正确地接受中文参数了。当然,这种方式也存在弊端,试想下当项目发布后,如果需要修改编码为GBK,则要修改源代码,而对客户而言,这需要反编译等步骤直接修改代码,有点困难。

四、通过web项目的WebRoot/WEB-INF/web.xml文件进行配置参数,同时可在servlet中进行读取。
web.xml的示例核心代码如下:

  1. <servlet>

  2.     <servlet-name>login</servlet-name>

  3.     <servlet-class>cn.hncu.servlets.LoginServlet</servlet-class>

  4.     <init-param>

  5.         <param-name>character</param-name>

  6.         <param-value>GBK</param-value>

  7.     </init-param>

  8. </servlet>

servlet示例核心代码如下:

  1. public void init(ServletConfig config) throws ServletException {

  2.     String charset = config.getInitParameter("character");

  3.     System.out.println(charset);

  4. }

这种方法弥补了方法3的缺陷,方便后期维护和修改,用户修改时不需要改源代码,只需修改web.xml即可。

<think>我们正在解决上传文件,通过multipart/form-data方式提交,服务端获取到的文件名出现中文乱码的问题。根据引用[1][3]等,核心原因是编码不一致,通常客户端发送没有正确设置UTF-8编码,或者服务端解析没有使用UTF-8编码。 解决方案分为客户端和服务端两个角度: 一、客户端(发送方)解决方案: 1. 在构造multipart请求,显式设置文件名部分的编码为UTF-8。具体做法是使用RFC 5987标准,即使用`filename*`参数,并指定编码和语言(通常为UTF-8和空语言),然后将文件名进行URL编码(百分号编码)。 例如:`Content-Disposition: form-data; name="file"; filename*=UTF-8''%E4%B8%AD%E6%96%87.txt` 注意:这里`UTF-8''`后面紧跟的是经过URL编码的文件名(如“中文.txt”编码后为`%E4%B8%AD%E6%96%87.txt`)。 2. 如果客户端使用的是某些框架(如RestAssured),需要配置框架的multipart默认编码为UTF-8。如引用[3]所示: ```java RestAssured.config = RestAssured.config() .multiPartConfig(multiPartConfig().defaultCharset("UTF-8")); ``` 3. 为了兼容旧浏览器,可以同提供`filename`和`filename*`两个参数,如: ``` Content-Disposition: form-data; name="file"; filename="fallback.txt"; // 这里的fallback.txt可以是旧编码下的文件名,但尽量用英文 filename*=UTF-8''%E4%B8%AD%E6%96%87.txt ``` 这样新客户端会识别`filename*`,旧客户端则使用`filename`。 二、服务端(接收方)解决方案: 1. 如果服务端使用Spring框架,可以配置MultipartResolver的默认编码为UTF-8。例如在XML配置中: ```xml <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"/> </bean> ``` 或者在Java配置中: ```java @Bean public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setDefaultEncoding("UTF-8"); return resolver; } ``` 2. 如果服务端无法修改配置,或者配置后仍然乱码,可以尝试在获取文件名后手动转换编码。例如,在Java中,如果原始文件名是ISO-8859-1编码的字节序列(这是Tomcat等容器的默认行为),那么可以这样转换: ```java String originalFileName = multipartFile.getOriginalFilename(); String correctFileName = new String(originalFileName.getBytes("ISO-8859-1"), "UTF-8"); ``` 注意:这种方式依赖于服务端容器将原始字节错误地解释为ISO-8859-1,然后我们重新用UTF-8解码。但这种方法并不通用,因为有些容器可能不是这样处理的。 3. 服务端应优先使用支持RFC 5987的解析库,这样可以直接解析`filename*`参数,从而获得正确的文件名。 三、其他注意事项: - 确保整个请求的Content-Type头部指定了字符集,例如:`Content-Type: multipart/form-data; charset=UTF-8; boundary=...`。但注意,根据标准,multipart的边界(boundary)部分并不使用该字符集,而是每个part可以有自己的字符集。因此,更推荐在每个part的Content-Disposition头部单独指定。 - 测试,可以使用工具(如Postman)发送请求,并检查请求头中的文件名部分是否按照上述格式设置。 总结:最可靠的方法是客户端使用`filename*`并指定UTF-8编码,服务端使用支持该标准的解析库,并配置为UTF-8编码。 下面是一个简单的流程图,说明解决乱码问题的步骤: ```mermaid graph TD A[客户端] -->|1. 设置filename*=UTF-8''并URL编码文件名| B(网络传输) B -->|2. 服务端使用UTF-8解析| C[服务器] C -->|3. 存储或显示文件名| D[正常显示中文] ``` 如果按照上述方法仍然无法解决,可能需要检查整个请求处理链中是否有其他环节修改了编码(如过滤器、拦截器等)。 相关问题: 1. 如何测试multipart/form-data请求的编码是否正确? 2. 当服务端无法修改,客户端如何强制解决文件名乱码? 3. 除了UTF-8,还有其他编码能解决中文乱码问题吗? 4. 如何批量处理已存储的乱码文件名?</think>### Multipart Form Data 文件名乱码的完整解决方案 #### 一、问题根源分析 文件名乱码的根本原因是**编码不一致**: 1. 客户端发送未使用 UTF-8 编码(如 RestAssured 默认 ASCII 编码[^3]) 2. 服务端解析未正确识别 UTF-8 编码 3. 未遵循 RFC 5987 标准处理带特殊字符的文件名 --- #### 二、客户端解决方案(发送方) 1. **强制指定 UTF-8 编码(通用方案)** ```java // Java 示例:显式设置 UTF-8 编码[^1][^3] String encodedName = "=?UTF-8?B?" + Base64.getEncoder().encodeToString("中文文件.txt".getBytes()) + "?="; part.setFileName(encodedName); ``` 2. **RestAssured 框架配置** ```java // 修复 RestAssured 默认 ASCII 编码问题[^3] RestAssured.config = RestAssured.config() .multiPartConfig(multiPartConfig().defaultCharset("UTF-8")) .httpClient(httpClientConfig().httpMultipartMode(HttpMultipartMode.BROWSER_COMPATIBLE)); ``` 3. **浏览器兼容格式(HTML表单)** ```html <form action="/upload" method="post" enctype="multipart/form-data" accept-charset="UTF-8"> <input type="file" name="file" accept=".txt"> </form> ``` --- #### 三、服务端解决方案(接收方) 1. **Spring Boot 全局配置** ```yaml # application.yml spring: servlet: multipart: enabled: true charset: UTF-8 file-size-threshold: 2KB ``` 2. **手动解码文件名** ```java // Java 服务端处理乱码[^1] public String decodeFileName(String rawName) { if (rawName.startsWith("=?UTF-8?B?")) { String base64 = rawName.substring(10, rawName.length()-2); return new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8); } return rawName; // 非UTF-8格式直接返回 } ``` 3. **Tomcat 服务器配置** ```xml <!-- conf/server.xml --> <Connector port="8080" URIEncoding="UTF-8" useBodyEncodingForURI="true" /> ``` --- #### 四、协议层规范(RFC 5987) 正确的内容头格式: ```http Content-Disposition: form-data; name="file"; filename="fallback.txt"; # 兼容旧浏览器的英文名 filename*=UTF-8''%E4%B8%AD%E6%96%87.txt # UTF-8编码文件名[^2] ``` 关键点: 1. `filename*` 使用百分号编码(如 `中文.txt` → `%E4%B8%AD%E6%96%87.txt`) 2. 语言标识可为空(`UTF-8''`) 3. 分号后必须保留空格 --- #### 五、全链路解决方案流程图 ```mermaid graph LR A[客户端] -->|1. 设置 filename*=UTF-8''| B(网络传输) B -->|2. Content-Type: multipart/form-data; charset=UTF-8| C[服务端] C -->|3. 配置UTF-8解析| D(Spring/Tomcat) D -->|4. 存储UTF-8文件名| E[正常显示] ``` > **黄金法则**:客户端发送 + 网络传输 + 服务端解析 全程强制 UTF-8 编码[^1][^3] --- ### 相关问题 1. 如何测试 multipart 请求的编码是否正确? 2. 当服务端无法修改配置,客户端如何强制解决文件名乱码? 3. 除了 Base64,还有哪些编码方式能解决特殊字符问题? 4. 如何批量修复已存储的乱码文件名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值