当表单以multipart/form-data形式提交时,UTF-8文本会出现乱码问题。

60

我正在上传文件到服务器。文件上传 HTML 表单有 2 个字段:

  1. 文件名 - 一个 HTML 文本框,用户可以使用任何语言来命名。
  2. 文件上传 - 一个 HTML 'file',用户可以从磁盘中指定要上传的文件。

当提交表单时,文件内容能够被正确接收。但是,当读取文件名(上面的第1点)时,它是乱码。ASCII 字符能正常显示,但是当名称用其他语言(德语、法语等)输入时,就会出现问题。

在 servlet 方法中,请求的字符编码被设置为 UTF-8。我甚至尝试了如下所述的过滤器 - 如何使这个代码提交一个带有 jQuery/Ajax 的 UTF-8 表单文本区域工作? - 但似乎没有起作用。只有文件名看起来是乱码的。

MySQL 表格支持 UTF-8 编码,文件名存储和显示都没有问题。我随机输入了一些非英文字符,它们都被正确地存储/显示。

通过 Fiddler,我监视了请求,所有的 POST 数据都正确传递。我正在尝试确定数据在哪里/如何变为乱码。感谢任何帮助。


我从https://dev59.com/9HE95IYBdhLWcg3wKq2q#2424824中受益 - 具体来说,是@MultipartConfig解决方案对我有用(除此之外,我还需要使用new String(....getBytes(...), ...))。到目前为止,在这里列出的其他解决方案不幸地不能单独为我工作 :/ - Vin
14个回答

58
我在使用Apache commons-fileupload时遇到了同样的问题。 我没有找出导致问题的原因,尤其是因为我在以下位置都使用了UTF-8编码:

  1. HTML的meta标签
  2. 表单的accept-charset属性
  3. 每个请求上的Tomcat过滤器设置了"UTF-8"编码

-> 我的解决方案是将字符串特别从ISO-8859-1(或者是您平台的默认编码)转换为UTF-8:

new String (s.getBytes ("iso-8859-1"), "UTF-8");

希望能帮到你。
编辑:从Java 7开始,你也可以使用以下方法:
new String (s.getBytes (StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

1
不确定这是否有帮助,但是commons-fileupload(至少v1.2.1)具有逻辑,如果您没有配置其他值,则默认使用平台编码。请查看org.apache.commons.fileupload.FileUploadBaseheaderEncoding字段。 - matt b
转换俄语字符时,这个工具非常好用。太棒了!谢谢。 - Khasan 24-7
3
你也可以使用new String(s.getBytes(Charset.defaultCharset()), "UTF-8")。这行代码的作用是将字符串s从默认字符集转换为UTF-8字符集。 - Lucas Basquerotto
1
Philip,StandardCharsets是在Java 7中引入的,而不是8;-) - winne2
@DavidGarcíaGonzález 看起来根据RFC 6266,可以预期它始终是iso-8859-1,但这也指向了一个“正确”的解决方案,即如果客户端使用filename*(注意*),并将字符集指定为utf-8,则浏览器和服务器应该能够正确处理RFC 5987 - Rhubarb
显示剩余2条评论

29

只需使用Apache Commons Upload库。 在Tomcat的连接器中添加URIEncoding="UTF-8",并使用FileItem.getString("UTF-8")而不是没有指定字符集的FileItem.getString()。

希望这可以帮助到您。


5
应该给这个点赞,没有其他方法可以解决这个问题...即使尝试了过滤器、域/容器 XML 文件等等,只要使用 getString("UTF-8") 就可以解决即使其他事情没有完成。 - Pradyut Bhattacharya
2
FileItem.getString("UTF-8") 对我来说是解决方案。 - DLight
1
这是真的,如果使用Apache commons-fileupload模块,它就能正常工作: http://commons.apache.org/proper/commons-fileupload/using.html 我会使用它,因为它解决了问题。 - Mariusz Jaskółka
这就是它,这是正确的答案。这帮助我处理带有附件的Unicode字符。非常感谢@nautilusvn,你救了我的一天! - Sachidananda Naik

21

我陷入了这个问题,并发现调用的顺序是关键。

request.setCharacterEncoding("UTF-8");

问题的根源在于调用了一个不正确的方法。必须在任何对request.getParameter()方法的调用之前调用setCharacterEncoding()方法,因此我创建了一个特殊的过滤器,在我的过滤器链的顶部使用它。

https://rogerkeays.com/servletrequest-setcharactercoding-ignored


运行良好且非常简单。谢谢! - CHOI

14

我曾经遇到同样的问题,结果发现在过滤器中除了指定编码之外,还需要进行其他设置。

request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");

需要在表单中添加"acceptcharset"属性

<form method="post" enctype="multipart/form-data" acceptcharset="UTF-8" > 

并且运行JVM

-Dfile.encoding=UTF-8

如果您在HTTP头中使用response.setCharacterEncoding()发送HTML meta标签,则不需要它。


4
我正在使用 Glassfish 3.1.1,虽然在 JVM 中使用 -Dfile.encoding=UTF-8 是必要的,但我并不需要过滤器。然而,只是简单地向 <form /> 标签添加 acceptcharset 属性并不能解决问题。相反,我需要将字符集标识符添加到 enctype 属性中,例如:<form enctype="multipart/form-data;charset=UTF-8"> - Kevin Rahe
2
-Dfile.encoding=UTF-8参数非常重要。 - Jasper

9

3
在Spring的另一个问题中,提到MultipartResolver的默认解码字符集为ISO-8859-1。官方的Spring文档中可以查看到这个设置:CommonsFileUploadSupport#setDefaultEncoding。请注意,该翻译尽可能保留原文意思,并简化语言以使其更易理解。 - easoncxz
XML格式: <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"/> </bean> - zoirs

3

我正在使用org.apache.commons.fileupload.servlet.ServletFileUpload.ServletFileUpload(FileItemFactory),并在读取参数值时定义编码:

List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);

for (FileItem item : items) {
    String fieldName = item.getFieldName();

    if (item.isFormField()) {
        String fieldValue = item.getString("UTF-8"); // <-- HERE

2

对于IE浏览器,过滤器非常关键。需要检查的其他几件事情包括:

页面编码和字符集是什么?两者都应该是UTF-8。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
标签中的字符集是什么?
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

你的MySQL连接字符串是否指定了UTF-8? 例如:

jdbc:mysql://127.0.0.1/dbname?requireSSL=false&useUnicode=true&characterEncoding=UTF-8

1
我正在使用Primefaces与Glassfish和SQL Server。
在我的情况下,我创建了Webfilter,在后端获取每个请求并将其转换为UTF-8,如下所示:
package br.com.teste.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(servletNames={"Faces Servlet"})
public class Filter implements javax.servlet.Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);      
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub      
    }

}

在视图 (.xhtml) 中,我需要将 enctype 参数的表单设置为 UTF-8,就像 @Kevin Rahe 所说的那样:
    <h:form id="frmt" enctype="multipart/form-data;charset=UTF-8" >
         <!-- your code here -->
    </h:form>  

0

您还需要确保在web.xml中,您的编码过滤器(org.springframework.web.filter.CharacterEncodingFilter)在多部分过滤器(org.springframework.web.multipart.support.MultipartFilter)之前被映射。


0

如果您通过URL的查询字符串传递数据,例如使用HTTP GET方法,那么过滤器和设置Tomcat以支持UTF-8 URI就变得非常重要。但是,如果您使用带有HTTP消息正文中查询字符串的POST方法,则请求的内容类型将非常重要,并且浏览器将设置内容类型为UTF-8并使用该编码发送内容。

唯一真正实现此目的的方法是通过在每个响应上设置Accept-Charset标头来告诉浏览器您只能接受UTF-8,例如"UTF-8;q=1,ISO-8859-1;q=0.6"。这将把UTF-8作为最佳质量和默认字符集,ISO-8859-1作为可接受的较低质量。

当您说文件名混乱时,它是否在HttpServletRequest.getParameter的返回值中出现乱码?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接