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(),这样对字符集的设置也是无效的。
相关推荐
musenh5 小时前
servlet入门
servlet
wfsm1 天前
flowable使用01
java·前端·servlet
六件套是我2 天前
redission实现延时队列
android·java·servlet
非典型代码3 天前
Jenkins发不出邮件
运维·servlet·jenkins
佐杰3 天前
Jenkins安装部署
运维·servlet·jenkins
chxii4 天前
Spring Boot 中,内嵌的 Servlet 容器(也称为嵌入式 Web 服务器)
spring boot·servlet
BUG?不,是彩蛋!4 天前
Maven-Java 项目到底解决了什么痛点?
java·servlet·maven
CS Beginner8 天前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
一只小透明啊啊啊啊11 天前
Java Web 开发的核心组件:Servlet, JSP,Filter,Listener
java·前端·servlet
芙蓉王真的好112 天前
优化 Jenkins 构建脚本:避免 pnpm lockfile 相关报错的关键配置
spring·servlet·jenkins