JSP中文亂碼問題終極解決方案(上)
摘要:
本文首先介紹了一個JSP的原始檔執行過程,即需要經過三個階段,兩次編碼,才能完成一次完整的輸出。特別需要注意的是,在這個過程中,編碼問題貫穿始終。我們知道在JSP/Servlet中,主要有以下四種方式可以設定編碼,即 pageEncoding、contentType、request.setCharacterEncoding 和 response.setCharacterEncoding,在本文中,我們就這四種方式進行深入的介紹和總結。
一. JSP的執行過程與編碼設定概述
在JSP/Servlet中,主要有以下四種方式可以設定編碼,其中前兩個只能應用於JSP中,而後兩個可以用於 JSP 和 Servlet 中。
- pageEncoding=”UTF-8”;
- contentType=”text/html;charset=UTF-8”;
- request.setCharacterEncoding(“UTF-8”) ;
- response.setCharacterEncoding(“UTF-8”)。
事實上,一個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”
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”
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”)
request.setCharacterEncoding(“UTF-8”)用來指定對瀏覽器傳送來的資料以特定的字符集進行重新編碼,常用於對 POST 請求引數進行解碼。具體見我的博文 《JSP中文亂碼問題終極解決方案(下)》中 “POST 請求的請求引數為中文情形” 一節。
四. response.setCharacterEncoding(“UTF-8”)
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編譯成Servlet時使用的編碼時,優先順序為: pageEncoding=”UTF-8” > contentType=”text/html;charset=UTF-8”
在指定伺服器對響應內容的編碼時,優先順序為:response.setCharacterEncoding(“UTF-8”) > contentType=”text/html;charset=UTF-8” > pageEncoding=”UTF-8”
request.setCharacterEncoding(“UTF-8”) 只用來指定對瀏覽器傳送來的請求資料的解碼方式。
更多關於 JSP技術的細節見我的其他兩篇部落格: 《Java Web基礎 — Jsp 綜述(上)》 和 《Java Web基礎 — Jsp 綜述(下)》。
更多關於 JSP中文亂碼問題的解決方案見我的另一篇部落格:《 JSP中文亂碼問題終極解決方案(下)》。
引用
關於JSP頁面中的pageEncoding和contentType兩種屬性的區別
JSP裡ContentType ,charset和pageEncoding的理解與區別
相關文章
- JSP中文亂碼問題終極解決方案JS
- SecureCRT 下MySQL中文亂碼問題終極解決方案SecurecrtMySql
- JavaWeb 亂碼問題終極解決方案!JavaWeb
- Linux中文亂碼問題終極解決方法Linux
- vim、gvim在windows下中文亂碼的終極解決方案Windows
- python 中文亂碼問題解決方案Python
- JSP開發過程遇到的中文亂碼問題及解決方案JS
- oracle 輸出中文亂碼問題解決方案Oracle
- 解決中文亂碼問題
- [原創]Gerrit中文亂碼問題解決方案分享
- eclipse 中文亂碼問題解決方案彙總Eclipse
- MySql中文亂碼問題解決MySql
- Jmeter 解決中文亂碼問題JMeter
- Java 解決中文亂碼問題Java
- RDSSQLSERVER解決中文亂碼問題SQLServer
- 解決MySQL中文亂碼問題MySql
- 解決plsql中中文亂碼問題SQL
- 解決JSP讀寫MYSQL亂碼問題JSMySql
- jsp頁面中中文亂碼問題JS
- linux使用vim(vi)中文亂碼的終極解決辦法Linux
- JSP顯示中文問題的解決方案(轉)JS
- java中解決request中文亂碼問題Java
- SpringMvc解決Restful中文亂碼問題SpringMVCREST
- 讀mysql中文亂碼問題解決方法MySql
- DES加密中文亂碼問題的解決加密
- Jenkins Git 中文亂碼問題解決JenkinsGit
- CentOS中文亂碼問題的解決方法CentOS
- JSP頁面裡中文的亂碼問題JS
- 斑竹!使用您的終極解決中文方法,還是出現亂碼
- shell指令碼中文註釋亂碼問題(解決)指令碼
- [轉]Linux系統出現亂碼問題的終極解決方法(轉)Linux
- 雲伺服器中文亂碼問題解決伺服器
- SqlServer資料庫中文亂碼問題解決SQLServer資料庫
- Sublime Text 3 中文亂碼問題的解決
- filezilla裡怎麼解決中文亂碼問題
- iOS 解決列印 NSDictionary 時,中文亂碼問題iOS
- 使用Kettle抽取資料時,出現中文亂碼問題解決方案
- git version 2.5.0.windows.1中文亂碼問題解決方案GitWindows