Servlet中的亂碼問題及解決辦法


假設現在有個form表單,當頁面中提交一個包含中文的請求時,在服務端有可能出現中文亂碼問題。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="registerServlet" method="POST">
		姓名:<input type="text" name="name"><br>
		年齡:<input type="text" name="age"><br>
		<input type="submit" value="注冊">
	</form>
</body>
</html>

 亂碼的產生原因

  Http協議中規定,數據的傳輸采用字節編碼方式,即無論瀏覽器提交的數據所包含的中文是什么字符編碼格式,一旦由瀏覽器經過Http 協議傳輸,則這些數據均將以 字節的形式上傳給服務器。 因為 HTTP 協議的底層使用的是 TCP 傳輸協議。 TCP (Transmission Control Protocol) 傳輸控制協議 ,是一種面向連接的、可靠的、基於字節流的、端對端的通信協議。在請求中,這些字節均以 開頭,並以十六進制形式出現。如 %5A%3D 等。

  當用戶通過瀏覽器提交一個包含 UTF 8 編碼格式的兩個字的中文請求時,瀏覽器會將這兩個中文字符變為六個字節(一般一個 UTF 8 漢字占用三個字節),即形成六個類似 %8E 的字節表 示形式,並將這六個字節上傳至 Tomcat 服務器。Tomcat 服務器在接收到這六個字節后,並不知道它們原始采用的是什么字符編碼。而Tomcat 默認的編碼格式為 ISO 8859-1 。所以會將這六個字節按照 ISO 8859-1 的格式進行編碼,這種編碼方式不支持中文,這樣就出現了亂碼。

關於請求的亂碼的解決方案

一、針對POST提交方式的解決方案

 

 

 

 

<!--
設置了請求正文的字符編碼,服務器解碼的時候會按照UTF-8解碼
但是這種方式對於GET方式的請求不適用,因為只對請求正文有作用,
GET方式的請求正文為空行,請求的參數出現在請求行
-->
request.setCharacterEncoding("UTF-8");

 二、針對GET提交方式的解決方案

  對於GET方式提交的情況,上述中設置request.setCharacterEncoding("UTF-8");是不會起作用的,因為GET方式的請求參數是在請求行

  目前了解的兩種解決方案:

  ①Tomcat的版本影響,我自己試了一下Tomcat的7.*版本的,什么都不設置的話,會有亂碼,但是用7.*以上的Tomcat服務器8.*,9.*的版本就不會出現亂碼

  ②當我們以GET方式向服務器提交數據的話,在地址欄中,URL中URI部分的參數提交的中文會以字節的方式顯示,對於請求路徑中所攜帶參數的解析,由 Tomcat 服務器完成。而 Tomcat 服務器的字符編碼默認為 ISO8859-1 ,所以會將請求路徑中所攜帶的數據,按照 ISO8859 1 進行編碼。

 

  這種情況下我們可以通過修改 Tomcat 默認字符編碼的方式來解決 GET 提交方式中攜帶中文的亂碼問題。在 Tomcat 安裝目錄的 conf/server.xml 中,找到端口號為 8080 的 <Connector>標簽,在其中添加 URIEncoding=UTF-8 的設置,即可將 Tomcat 默認字符編碼修改為 UTF-8 。

(不建議,如果服務器有多個虛擬服務器,修改后會重啟多個應用程序)

三、萬能的解決方案(比較通用但是還是有弊端)

 

String name = request.getParameter("name");
byte[] bytes = name.getBytes("ISO8859-1");
name = new String(bytes, "UTF-8");

 

  該方式無需設置Tomcat 中的 server.xml 中的 Tomcat 默認字符編碼,無需設置 request的請求體的字符編碼。從數據在請求中的存放形式,到數據被Tomcat 中的 Servlet 接收到后的存放形式,均是由單個字 節的形式存在,而在眾多字符編碼格式中, ISO8859-1 為單字節編碼,所以,首先以 ISO8859 -1 的形式先對單字節的數據進行編碼,並將編碼后的數據存放在字節數組中。然后,再將字節數組中的數據,按照指定的 UTF -8 格式進行解碼,即變為了需要的 UTF- 8 字符編碼的數據,解決了中文亂碼問題。

  編碼,即重新編排,即打散,將字符串 打散后按照指定編碼進行重新編排。 這里的編碼使用的是 String 的 getBytes() 方法,完成的工作是:按照當前字符編碼將數據打散。

  解碼,即解釋執行,即組裝,對打散的字符按照指定編碼組裝后進行解釋執行。 這里的解碼使用的是StringString的帶參構造器,完成的工作是:按照原有字符編碼將數據組裝。的帶參構造器,完成的工作是:按照原有字符編碼將數據組裝。

該方式針對POST與與GET提交方式,均起作用。

 

響應的亂碼問題

產生原因之所以響應時會產生亂碼,是因為 HTTP 協議中規定,默認響應體的字符編碼為ISO-8859-1 。所以,若要解決亂碼問題,就需要修改響應體的默認編碼。

解決方案:

response.setContentType("text/html“);//設置MIME類型
response.setCharacterEncoding("UTF-8");

 

  修改 MIME 的字符編碼,即修改響應體的字符編碼。但使用 setCharacterEncoding() 方法的前提是,之前必須要通過使用方法 setContentType() 方法設置響應內容的 MIME 類型。否則 setCharacterEncoding() 方法不起作用。

 

response.setContentType("text/html;charset=UTF-8");

 用於 設置響應 內容 的 MIME 類型 ,其中可以指定 MIME 的字符編碼。而 MIME 的字符編碼,即響應體的字符編碼 。

 

 

 

 ①②是一樣的,沒啥區別!!!

  瀏覽器會根據響應體字符編碼,自動調整其對響應體內容的解碼方式,即會使用響應體的字符編碼顯示響應體內容。不過,需要注意一點,這些設置,必須在PrintWriter 對象產生之前先設置,否則將不起作用。

 

 重定向的亂碼解決方式

 

//底層按字節流傳輸,打散
name = URLEncoder.encode(name, "UTF-8");

//另一邊接收
//組裝
name = URLDecoder.decode(name, "UTF-8");
byte[] bytes = name.getBytes("ISO8859-1");
name = new String(bytes, "UTF-8");

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM