Servlet之乱码问题处理

文章目录

    • 乱码问题
      • 1. 判断字符串的编码格式
      • 2. 获取 GET 请求中的数据,打印乱码
      • 3. 获取 POST 请求中的数据,打印乱码
      • 4. 中文字符串,输出到页面显示乱码
      • 5. setContentType 和 setCharacterEncoding

乱码问题

1. 判断字符串的编码格式

注意,由于存在重码现象,以下方案并不严谨

// 由于字符编码存在重叠区,所以一个字符/字符串有多种编码可能,是完全正常合理的。
public static String getEncoding(String str) {
    String encode[] = new String[]{
            "ASCII",
            "ISO-8859-1",
            "GB2312",       // GB2312 是 GBK 的一种「具体情况」。
            "GBK",
            "UTF-8",        // UTF-8 是 Unicode 的一种「具体情况」。
            "UTF-16",       // UTF-16 是 Unicode 的一种「具体情况」。
            "Unicode",
    };
    String ret = "";

    for (int i = 0; i < encode.length; i++) {
        try {
            if (str.equals(new String(str.getBytes(encode[i]), encode[i]))) {
                ret = ret + encode[i] + " ";
            }
        } catch (Exception ex) {
        }
    }

    return ret.equals("") ? "Other" : ret;
}

乱码出现在三种场景:

  • GET 请求提交的中文数据,在 Servlet 中输出乱码。

  • POST 请求提交的中文数据,在 Servlet 中输出乱码。

  • 返回给浏览器的中文数据,在页面显示乱码。

提前声明,虽然同样是提交的数据在 Servlet中 显示为乱码,但是 GET / POST 发生乱码的原因和解决乱码的方案并不相同,不能混用 。

2. 获取 GET 请求中的数据,打印乱码

默认情况下,浏览器发送给 Tomcat 的数据都是以 ISO-8859-1 进行编码后的字节流。

在 get 请求中,Tomcat 以何种方式看待、解析接收的这些字节流取决于 server.xml 中的一个配置:

默认情况下 URIEncoding="ISO-8859-1",即 Tomcat 默认以 ISO-8859-1 编码解析所收到的 get 请求发送来的字节流,从而转换为字符流,即字符串。

但是这里有一个关键性问题:Java 字符串是 UTF-8 编码。所以,当你通过 req.getParameter(""); 获得一个中文字符串时,这个字符串是 ISO-8859-1 编码,但一旦你使用 System.out.println() 打印时,Java 会当它是一个 UTF-8 编码的字符串。这就是出现乱码原因。

解决问题的办法有两个:

  1. 修改配置文件,让 Tomcat 以 UTF-8 格式 看待/解析 接收到的字节流。

  2. 不改变配置文件。获得 Tomcat 的 ISO-8859-1 字符串后,生成对应的 UTF-8 字符串,再进行输出打印。

3. 获取 POST 请求中的数据,打印乱码

serverl.xml 中 URIEncoding="xxx" 设置影响不到 post 请求提交来的数据!适用于 get 请求的修改配置方案,对 post 请求无效!

Tomcat 如何 看待/解析 post 请求发送来的数据,取决于 req.setCharacterEncoding("");。如果未曾调用该方法,Tomcat 以 ISO-8859-1 编码解析接受的post请求数据。同上,随后一旦调用 System.out.println() 就会出现乱码。

解决问题的办法有两个:

  1. 在调用 req.getParameter() 前调用 req.setCharacterEncoding("UTF-8");, 让 Tomcat 以 UTF-8 格式 看待/解析 接收到的字节流

  2. 不设置req字符编码。获得 Tomcat 的 ISO-8859-1 字符串后,生成对应的 UTF-8 字符串,再进行输出打印。

如同 get 的方案一对 post 无效,post 的方案一同样解决不了 get 的乱码问题。

但是,显而易见,两者方案二是相同的,这也是后续 过滤器 的主要使用场景。

4. 中文字符串,输出到页面显示乱码

以何种编码将字符转换为字节流后,发送给浏览器,取决于 resp.setCharacterEncoding("xxx"); 。没有调用时,默认使用 ISO-8859-1 编码格式。

但是 ISO-8859-1 格式最大的问题在于:它是一个单字节编码,不支持中文。

所以,使用 Tomcat 默认的 ISO-8859-1 编码向浏览器发送的字节流中,如果含有中文信息,浏览器无法正确显示成对应中文。

解决办法只有一个,设置 Tomcat 发送数据的编码格式,并且,resp.setCharacterEncoding() 必须在 PrintWriter out = resp.getWriter(); 之前,否则设置无效(因为你已经得到了使用 ISO-8859-1 编码的 out 对象了)

5. setContentType 和 setCharacterEncoding

servletResponse.setCharacterEncoding() 方法的注释中写到了它和 setContentType 之间的关系:

  • 如果 response 的字符集已经在 setContentType(或 setLocale)方法中指定,那么你再调用 setCharacterEncoding 方法则会覆盖掉之前的设置。
  • .setContentType("text/html; charset=UTF-8") 等同于 .setContentType("text/html") + .setCharacterEncoding("UTF-8")

另外,在使用 setCharacterEncoding 会出现失效的情况,通常是因为 2 点原因:

  1. 你在 .getWriter() 之后才调用 .setCharacterEncoding(),这样对字符集的设置太晚,自然是无效的。
  2. 你有 .setCharacterEncoding(),但是没有调用 .setContentType(),这样对字符集的设置也是无效的。

你可能感兴趣的:(servlet,servlet)