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的理解與區別
相關文章
- JavaWeb 亂碼問題終極解決方案!JavaWeb
- 解決中文亂碼問題
- Linux終端中文菱形亂碼解決方案Linux
- springmvc 解決中文亂碼問題SpringMVC
- MySql中文亂碼問題解決MySql
- Jmeter 解決中文亂碼問題JMeter
- js解決url中文亂碼問題JS
- 解決plsql中中文亂碼問題SQL
- whisper v3 finetune 中文亂碼問題的解決方案
- phantomjs截圖中文亂碼問題解決JS
- 雲伺服器中文亂碼問題解決伺服器
- 解決Url帶中文引數亂碼問題
- Sublime Text 3 中文亂碼問題的解決
- python json.dumps中文亂碼問題解決PythonJSON
- SqlServer資料庫中文亂碼問題解決SQLServer資料庫
- 完美解決jspdf各種中文亂碼問題JS
- 解決zabbix圖形化中文亂碼問題
- LiveCharts中文顯示亂碼問題的解決Echarts
- 使用Kettle抽取資料時,出現中文亂碼問題解決方案
- Tomcat配置jsp亂碼問題TomcatJS
- JMeter響應亂碼問題解決方案教程JMeter
- 解決Eclipse中文註釋部分亂碼的問題Eclipse
- URL地址中的中文亂碼問題的解決
- Mysql中文亂碼問題的最佳解決方法MySql
- css中文字型亂碼解決方案CSS
- navicat for mysql顯示中文亂碼解決方案MySql
- 解決PHP匯出CSV檔案中文亂碼問題PHP
- IDEA裡Tomcat Console日誌中文亂碼問題解決IdeaTomcat
- HttpClient多檔案上傳程式碼及普通引數中文亂碼問題解決HTTPclient
- 如何解決PuTTY中文亂碼的問題
- mysql5.7.22設定中文編碼-解決亂碼問題LinuxMySqlLinux
- vscode中文亂碼問題VSCode
- EasyUI 中文亂碼問題UI
- 解決ajax get post方式提交中文引數亂碼問題
- linux 安裝字型解決JAVA圖形中文亂碼問題LinuxJava
- 常見php與mysql中文亂碼問題解決辦法PHPMySql
- MySQL解決中文亂碼MySql
- Python:Python中文寫入csv檔案出現亂碼問題的解決方案之一Python
- python爬蟲爬取網頁中文亂碼問題的解決Python爬蟲網頁