1. 看看规范怎么说
contentType 和 pageEncoding 是 JSP 的 page 指令中的两个属性,我们首先看看 JSP2.3 规范是怎么描述它们的。
1.1 contentType
Defines the MIME type and the character encoding for the response of the JSP page, and is also used in determining the character encoding of the JSP page.
Values are either of the form “TYPE” or “TYPE;char-set=CHARSET”with an optional white space after the “;”. “TYPE” is a MIME type, see the IANA registry at http://www.iana.org/assignments/media-types/index.html for useful values. “CHARSET”, if present, must be the IANA name for a character encoding.
The default value for “TYPE” is “text/html” for JSP pages in standard syntax, or “text/xml” for JSP documents in XML syntax. If “CHARSET” is not specified, the response character encoding is determined as described in Section JSP.4.2, “Response Character Encoding”.
The corresponding JSP configuration element is default-content-type (see Section JSP.3.3.9, “Declaring Default Content Type”). See Chapter JSP.4, “Internationalization Issues” for complete details on character encodings.
该属性定义 JSP 页面响应内容的 MIME 类型和字符编码,也用来决定 JSP 页面的字符编码。
该属性的值要么是 “MIME 类型” 要么是 “MIME类型; charset=某字符集”,在分号后面带一个半角空格,后面跟着字符集设定内容。MIME 类型的相关信息可以参考 http://www.iana.org/assignments/media-types/index.html 。如果分号后面设定了字符集,那么设定值应该是规范的 IANA 名称。
在 JSP 标准语法中,MIME 类型的默认值为 “text/html”,或者 “text/xml”。如果不指定 charset,JSP 页面响应内容的字符编码取决于本规范的3.3.9部分的规则。
响应的 JSP 配置元素是 default-content-type(请参考本规范的3.3.9的说明)。更加详细的信息请参考本规范的第4章节。
简单说明两点。
第一,所谓 JSP 页面响应内容指的是浏览器向当前 JSP 页面发送请求,当前 JSP 页面处理请求后返回的 response 对象。更准确地说,是 response 对象中包含的静态 HTML 页面。浏览器收到该文件就可以渲染出来给用户看。
第二,所谓的 IANA 名称指的是 UTF-8,GBK 之类的编码名称,意思就是不要胡写。
1.2 pageEncoding
Describes the character encoding for the JSP page. The value is of the form “CHARSET”, which must be the IANA name for a character encoding. For JSP pages in standard syntax, the character encoding for the JSP page is the charset given by the pageEncoding attriute if it is present, otherwise the charset given by the contentType attribute if it is present, otherwise “ISO-8859-1”.
For JSP documents in XML syntax, the character encoding for the JSP page is determined as described in section 4.3.3 and appendix F.1 of the XML specification. The pageEncod-ing attribute is not needed for such documents. It is a translation-time error if a document names different encodings in its XML prolog / text declaration and in the pageEncoding attribute. The corresponding JSP configuration element is page-encoding (see Section JSP.3.3.4, “Declaring Page Encodings”).
See Chapter JSP.4, “Internationalization Issues” for complete details on character encodings.
该属性描述当前 JSP 页面的字符编码。属性值是字符集,它必须是规范的 IANA 字符集名称。在 JSP 的标准语法中,如果设定了 pageEncoding 属性,那么它的属性值应该作为当前 JSP 页面的编码。如果没有设定 pageEncoding 属性,那么把 contentType 属性值中定义的 charset 的值作为当前 JSP 页面的编码。如果 contentType 属性中没有设定 charset,那么把 ISO-8859-1 作为当前 JSP 页面的编码。
和 XML 相关的 JSP 语法的翻译略。
详细信息请参考本规范的第四章节。
1.3 结论
JSP 规范对 pageEncoding 的说明已经讲得很明白了,pageEncoding 代表的是当前 JSP 页面的编码类型。如果它没有被设定,JSP 引擎才会去找 contentType 中的 charset。由于 contentType 有两种形式,可以只写 MIME 类型,所以有可能 contentType 中也找不到字符编码,这种情况下,就把 ISO-8859-1 作为当前 JSP 页面的编码类型。
2. 还没完
2.1 关于 contentType
规范说的是 contentType 也 可以作为决定当前 JSP 页面编码的一种手段。这个“也”字用得非常好,因为这意味着 contentType 的主要作用并不是决定当前 JSP 页面的字符编码,而是用来决定 JSP 页面响应内容的字符编码的。
我们在编写 Servlet 的时候,一般会在调用 response.getWriter() 之前调用 response.setContentType(),用来设定响应类型。JSP 本质上也是一个 Servlet,JSP 引擎把 JSP 文件转换成 Java 文件的时候,会把我们在 JSP 页面的 page 指令中设定的 contentType 属性转换成 response.setContentType() 的形式。这个东西一方面决定了响应内容的编码格式,另一方面又以响应消息头(消息头中的Content-Type)的形式告诉浏览器应该用什么编码方式进行解码。响应内容的生成是由 Servlet 引擎完成的。比如 Servlet 引擎以 GBK 的形式对响应内容进行编码,并且在响应消息头中添加 Content-Type text/html;charset=GBK 的内容,在我们不加以干预的情况下,浏览器会自动按 GBK 进行解码。这样,编码方式和解码方式一致,就不会出现乱码。
2.2 关于 pageEncoding
JSP2.3 规范关于 pageEncoding 的第一句话是“该属性描述当前 JSP 页面的字符编码”,这里的“描述”用得也非常准确。因为 pageEncoding 只是描述当前 JSP 页面的字符编码,至于这个 JSP 文件是不是以该编码方式编码的,那可未必。pageEncoding 只是告诉 JSP 引擎把 JSP 文件转换成 Java 文件的时候应该以什么编码方式读取 JSP 页面的内容。
比如,我们不借助任何IDE工具,在本地手动新建一个JSP文件。默认情况下,这个JSP文件的编码方式是GBK。如果我们指定pageEncoding为UTF-8,相当于编码和解码不一致,那么中文乱码在所难免。
既然是在 JSP 引擎按照 pageEncoding 设定的编码格式读取 JSP 文件的时候出现的不一致,可以想见的是,在网页上出现乱码之前,由 JSP 文件生成的 Java 文件其实已经是乱码状态的了。
顺便提一下,JSP 引擎生成 .java 文件和 .class 文件的时候是以 UTF-8 格式编码的,但是这个不重要,重要的是 JSP 引擎读取 JSP 文件的时候采用的编码格式和 JSP 文件真正的编码格式是否一致。
如果使用 Eclipse 创建 JSP 文件,在文档中含有中文字符的情况下,Eclipse 会根据 pageEncoding 的值决定 JSP 文件的编码格式。如果修改了 pageEncoding 的编码设置,保存以后,JSP 文件的编码格式也会随之改变。这样就无形中保证了 JSP 页面的编码格式始终和 pageEncoding 的值一致,JSP 引擎读取该 JSP 文件的时候就不会出现编码不一致的情况。
2.3 关于中文乱码
中文乱码的情况有很多,原因无外乎写入时候的编码格式和读取时候的编码格式不一致。本文探讨的是最基本最简单的中文乱码情况,只需要保证 pageEncoding 的值和 JSP 文件的编码格式保持一致就行。至于有些人说的 pageEncoding 和 contentType 中的 charset 也要保持一致的话,其实从避免乱码的角度来说,并没有那样的强制要求,只不过处处保持一致使我们安心而已。
如图,pageEncoding 设置为 GBK,contentType 的 charset 设置为 UTF-8,并不会出现乱码。