Servlet之乱码问题处理

文章目录

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

乱码问题

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

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

java 复制代码
// 由于字符编码存在重叠区,所以一个字符/字符串有多种编码可能,是完全正常合理的。
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 中的一个配置: <Connector port="8080" ... URIEncoding="xxx"

默认情况下 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(),这样对字符集的设置也是无效的。
相关推荐
编程、小哥哥21 小时前
在 Docker 中部署 Jenkins,并完成项目的构建和发布
servlet·docker·jenkins
weixin_537590452 天前
《Java编程入门官方教程》第八章练习答案
java·开发语言·servlet
Ttang233 天前
Tomcat原理(4)——尝试手动Servlet的实现
java·开发语言·servlet·java-ee·tomcat·intellij-idea
loop lee4 天前
计算机网络 - HTTP 协议和万维网
java·网络协议·servlet·tomcat
不修×蝙蝠4 天前
搭建Tomcat(四)---Servlet容器
java·服务器·servlet·tomcat·搭建resquest
像污秽一样4 天前
简易记事本开发-(SSM+Vue)
java·vue.js·spring boot·spring·servlet·maven·mybatis
计算机学无涯6 天前
Servlet学习中遇到的一些问题及解决
servlet
测试工程师成长之路6 天前
解锁 Jenkins 搭建全攻略
运维·servlet·jenkins
进击的编程浪人6 天前
jsp中的四个域对象(Spring MVC)
servlet
怒放de生命20107 天前
jenkins 出现 Jenkins: 403 No valid crumb was included in the request
java·servlet·jenkins