摘要:
本文首先介绍了一个 JSP 的源文件执行过程,即需要经过三个阶段,两次编码,才能完成一次完整的输出。特别需要注意的是,在这个过程中,编码问题贯穿始终。我们知道在 JSP/Servlet 中,主要有以下四种方式可以设置编码,即 pageEncoding、contentType、request.setCharacterEncoding 和 response.setCharacterEncoding,在本文中,我们就这四种方式进行深入的介绍和总结。
在 JSP/Servlet 中,主要有以下四种方式可以设置编码,其中前两个只能应用于 JSP 中,而后两个可以用于 JSP 和 Servlet 中。
事实上,一个 JSP 的源文件需要经过三个阶段,两次编码,才能完成一次完整的输出,这三个阶段是:
第一阶段:转译(.jsp -> .java;pageEncoding -> UTF-8)。将 jsp 编译成 Servlet(.java)文件,用到的指令是 pageEncoding。在编译过程中,根据 pageEncoding="XXX" 的指示,找到编码的规则为 "XXX",然后服务器将 JSP 文件编译成. java 文件时会根据 pageEncoding 的设定读取 jsp,结果是由指定的编码方案翻译成统一的 UTF-8 编码的 JAVA 源码(即. java)。
第二阶段:编译(.java -> .class;UTF-8 -> UTF-8)。从 Servlet 文件(.java)到 Java 字节码文件(.class),从 UTF-8 到 UTF-8。在这一阶段中,不论 JSP 编写时候用的是什么编码方案,经过这个阶段的结果全部是 UTF-8 的 encoding 的 java 源码。JAVAC 用 UTF-8 的 encoding 读取 java 源码,编译成 UTF-8 编码的二进制码(即. class),这是 JVM 对常数字串在二进制码(Java encoding)内表达的规范。这一过程是由 JVM 的内在规范决定的,不受外界控制。
第三阶段:编译(UTF-8 -> contentType)。从服务器到浏览器,这在一过程中用到的指令是 contentType。服务器载入和执行由第二阶段生成出来 JAVA 二进制码,输出的结果,也就是在客户端可见到的结果,在这次输出过程中,由 contentType 属性中的 charset 来指定,将 UTF8 形式的二进制码以 charset 的编码形式来输出。如果没有人为设定,则默认的是 ISO-8859-1 的形式。
特别需要注意的是,pageEncoding 的默认值是 "ISO-8859-1", contentType 的默认值是 "text/html;ISO-8859-1"。
Ps: 第一、三两个阶段的转码个人感觉联想到 Sting 转码更容易理解些,例如 :new String(name.getBytes("ISO-8859-1"),"utf-8")。
pageEncoding="UTF-8" 的作用是设置 JSP 编译成 Servlet 时使用的编码。通常,在 JSP 内部定义的字符串(直接在 JSP 中定义,而不是从浏览器提交的数据)出现乱码时,很多都是由于该参数设置错误引起的。例如,你的 JSP 文件中含有中文字符,而在 JSP 中却指定 pageEncoding="iso-8859-1",就会导致中文字符显示异常。看下面的例子:
- <%@ page language="java" pageEncoding="iso-8859-1" import="java.util.*"
- %>
- <html>
- <head>
- <title>
- 哈哈
- </title>
- </head>
- <body>
- 中文
- <br>
- </body>
- </html>
在其编译为 Servlet 后,其源码(片段)如下所示:
- public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException,
- ServletException {
- // ...
- out.write("<html>\r\n");
- out.write(" <head>\r\n");
- out.write(" <title>?"??"?</title>\r\n");
- out.write(" </head>\r\n");
- out.write(" <body>\r\n");
- out.write(" \t ??-?–? <br>\r\n");
- out.write(" </body>\r\n");
- out.write("</html>\r\n");
- // ...
访问该页面,页面显示如下:
我们可以看到,由于 pageEncoding 被指定为 "iso-8859-1",导致其在由服务器将 JSP 文件编译成. java 文件过程中,在使用 "iso-8859-1" 读取 jsp 并翻译成统一的 UTF-8 编码的 JAVA 源码时,所有的中文字符被转成乱码,并使得其呈现给用户的响应也包含乱码。特别地,该属性还有一个功能,就是在 JSP 中不指定 contentType 参数,也不使用 response.setCharacterEncoding 方法时,指定对服务器响应的内容进行编码。
contentType="text/html;charset=UTF-8" 的作用是将上述第二阶段所生成的 UTF8 形式的二进制码以 charset 的编码形式来输出到客户端,如果设置不当的话,会出现乱码。看下面的例子:
- <%@ page language="java" contentType="text/html;iso-8859-1" import="java.util.*"
- pageEncoding="utf-8" %>
- <html>
- <head>
- <title>
- 哇哈哈
- </title>
- </head>
- <body>
- 哇哈哈
- <br>
- </body>
- </html>
在其编译为 Servlet 后,其源码(片段)如下所示:
- public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException,
- ServletException {
- // ...
- out.write("<html>\r\n");
- out.write(" <head>\r\n");
- out.write(" <title>哇哈哈</title>\r\n");
- out.write(" </head>\r\n");
- out.write(" <body>\r\n");
- out.write(" \t 哇哈哈 <br>\r\n");
- out.write(" </body>\r\n");
- out.write("</html>\r\n");
- // ...
访问该页面,页面显示如下:
request.setCharacterEncoding("UTF-8") 用来指定对浏览器发送来的数据以特定的字符集进行重新编码,常用于对 POST 请求参数进行解码。具体见我的博文 中 "POST 请求的请求参数为中文情形" 一节。
response.setCharacterEncoding("UTF-8") 的作用是:在服务器将响应返回到浏览器前,对响应使用指定字符集进行重新编码。一旦使用了该种方式,即使该响应页面指定了具体的 contentType,也将失效。看下面的例子:
- <%@ page language="java" contentType="text/html;iso-8859-1" import="java.util.*"
- pageEncoding="utf-8" %>
- <html>
- <head>
- <title>
- 哇哈哈
- </title>
- </head>
- <body>
- 哇哈哈
- <br>
- </body>
- </html>
在其编译为 Servlet 后,其源码(片段)如下所示:
- public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException,
- ServletException {
- // ...
- out.write("<html>\r\n");
- out.write(" <head>\r\n");
- out.write(" <title>哇哈哈</title>\r\n");
- out.write(" </head>\r\n");
- out.write(" <body>\r\n");
- out.write(" \t 哇哈哈 <br>\r\n");
- out.write(" </body>\r\n");
- out.write("</html>\r\n");
- // ...
访问该页面,页面显示如下:
根据上文内容,我们得出以下三点:
更多关于 JSP 技术的细节见我的其他两篇博客: 和 。
更多关于 JSP 中文乱码问题的解决方案见我的另一篇博客:。
来源: http://www.bubuko.com/infodetail-1964060.html