亂碼是一個常常出現的問題
請求中,參數傳遞的過程當中也是常常出現亂碼的問題
本文主要整理了請求亂碼中的問題以及解決思路
先要理解一個概念前提:
編碼就是把圖形變成數值碼因此說:
圖形的字符 ----> 字節數組 是編碼
字節數組-------->圖形的字符 是解碼
爲何會亂碼?
計算機數據只能是二進制的
數值類型的數據轉換成二進制很簡單,
但字符類型如何轉換成二進制呢?這就須要使用字符編碼!
在編碼表中,每一個字符都有對應的編碼,編碼是整數,最終在計算機中存儲的是字符的編碼
而不是字符自己(由於計算機數據都是二進制數值,因此字符自己是沒法存儲的)。
假如說兩種編碼
紅框1 橘色框 2 ,不用較真數值是多少,符號是什麼,只爲表達概念
每種編碼方式內部,字符和數值是一 一對應的
可是若是使用A------>65進行編碼
而後使用 65------>$ 另一種解碼方式解讀,顯然A就變成了$,這不就是亂碼了麼
不一樣的編碼方式不一樣,同一個字符的二進制也基本是不一樣的,若是沒有正確的進行解讀,那麼就會出現亂碼問題
發起請求時,不論是什麼字符,計算機都不認識,必須編碼轉換爲數值.
接收到請求的地方想要使用,就必須在編碼成爲字符
如何解決亂碼問題,也就是正確編碼的問題
請求響應的編碼問題
1.直接在地址欄中給出中文
請求數據是由客戶端瀏覽器發送服務器的,請求數據的編碼是由瀏覽器決定的。
例如在瀏覽器地址欄中給出:http://localhost:8080/servlet/AServlet?name=張三,那麼其中「張三」是什麼編碼的呢?
不一樣瀏覽器使用不一樣的編碼,因此這是不肯定的!
Chrome:使用UTF-8;
(這幾個說的不必定對,反正重點是要知道,不一樣的瀏覽器,直接地址欄輸入的參數的字符編碼是不固定的,也說不定將來或許會統一)
2. 響應編碼
當使用response.getWriter()來向客戶端發送字符數據時,若是在以前沒有設置編碼,那麼默認使用iso,由於iso不支持中文,必定亂碼
response.getWriter().println("ServletA");
response.getWriter().println("你好");
在使用response.getWriter()以前
可使用response.setCharacterEncoding()來設置字符流的編碼爲gbk或utf-8
固然咱們一般會選擇utf-8
response.setCharacterEncoding("utf-8");
這樣使用response.getWriter()發送的字符就是使用utf-8編碼的。但仍是會出現亂碼!
由於瀏覽器並不知道服務器發送過來的是什麼編碼的數據!這時瀏覽器通常會使用gbk來解碼,因此亂碼!
因此須要設置響應的編碼,以及通知瀏覽器應該使用何種編碼方式去解讀
在使用response.getWriter()以前
可使用
response.setHeader("Content-type","text/html;charset=utf-8")
來設置響應頭,通知瀏覽器服務器這邊使用的是utf-8編碼
並且在調用setHeader()後
還會自動執行setCharacterEncding()方法。
這樣瀏覽器會使用utf-8解碼,因此就不會亂碼了!
response.setHeader("Content-type","text/html;charset=utf-8");
response.getWriter().println("ServletA");
response.getWriter().println("你好");
setHeader("Content-Type", "text/html;charset=utf-8")的快捷方法是:
response.setContentType("text/html;charset=utf-8);
總結:輸出響應,想要不亂碼
只須要在使用getWriter()方法前:
response.setContentType("text/html;charset=utf-8);
若是是靜態頁面中,使用<meta>來設置content-type響應頭,例如:
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
補充說明:
UTF-8 中 三個字節表示一箇中文
E4BDA0=你 E5A5BD=好
發送的時候是UTF-8 也就是發送的 E4BDA0E5A5BD
GBK中兩個字節表示一箇中文
也就是
E4BD A0E5 A5BD
查表可得:
3.在頁面中發出請求
一般向服務器發送請求數據都須要先請求一個頁面,而後用戶在頁面中輸入數據。
頁面中有超連接和表單,經過超連接和表單就能夠向服務器發送數據了。
用戶在頁面中輸入的數據是由頁面自己的編碼決定的
又由於頁面是服務器發送到客戶端瀏覽器的,因此這個頁面自己的編碼又由服務器響應決定
|
|
服務器返回當前頁面的響應時,設置響應頭content-type,指定當前頁面的編碼爲utf-8
若是設置了那麼能夠經過瀏覽器查看響應信息看到
若是是
Content-Type:text/html; 而沒有後面的charset=utf-8
能夠看下輸出的響應頁面上是否有這一句,也是同樣的
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
歸根結底是看響應中是否有 Content-type utf-8 的相關信息 有了charset的信息,就按照他來
4.GET請求解讀編碼
使用request.getParameter()獲取的數據是被服務器誤認爲ISO-8859-1編碼的
也就是說客戶端發送過來的數據不管是UTF-8仍是GBK,服務器都認爲是ISO-8859-1
tomcat8之後默認編碼格式是utf-8;7以前的都是iso8859-1 |
是否須要在使用request.getParameter()獲取數據後,再轉發成正確的編碼
要看你實際使用的tomcat 版本
例如客戶端以UTF-8發送的數據,使用tomcat7 以及以前的版本
須要使用以下轉碼方式:html
String name = request.getParameter(「name」);
name = new String(name.getBytes(「iso-8859-1」), 「utf-8」);
重點是要理解邏輯:
tomcat 默認的使用某種編碼對傳遞過來的數據進行了解碼
若是說正好是咱們傳遞過來的,那麼不須要作處理
若是不是,就須要按照他解碼的方式,從新編碼成字符數組,在使用字節數組 按照編碼規則從新解碼爲字符串
(字符到字節數組是編碼 字節數組到字符是解碼)
示例:
在utf8頁面上 get請求 http://127.0.0.1:8080/servlet/ServletA?name=張三
Servlet中
String name = request.getParameter("name");
System.out.println("request.getParameter(\"name\"): "+name);
name = new String(name.getBytes("iso-8859-1"), "utf-8");
System.out.println("new String(name.getBytes(\"iso-8859-1\"), \"utf-8\"): "+name);
頁面是utf8 天然請求是utf8編碼規則
tomcat8 默認utf8 解碼
tomcat7 默認iso
固然也是能夠修改Server.xml中設置URIEncoding的值爲UTF-8
可是不建議這麼作,代碼不能依賴tomcat的設置,嚴重破壞可移植性
5.POST請求解讀編碼
當客戶端經過POST請求發送數據給服務器時,能夠在使用request.getParameter()獲取請求參數以前
先經過request.setCharacterEncoding()來指定編碼,而後再使用reuqest.getParameter()方法來獲取請求參數
也就是說,若是是POST請求,服務器能夠指定編碼!
但若是沒有指定編碼,那麼仍舊也仍是使用默認的來解讀
request.setCharacterEncoding(「utf-8」);
String name = request.getParameter(「name」);
6. URL編碼
POST表單提交的類型:
Content-Type: application/x-www-form-urlencoded |
- 首先,Content-Type 被指定爲 application/x-www-form-urlencoded;
- 其次,提交的數據按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。
- 大部分服務端語言都對這種方式有很好的支持。
其實就是把中文轉換成%後面跟隨兩位的16進制。
在客戶端和服務器之間傳遞中文時須要把它轉換成網絡適合的方式
不是字符編碼,客戶端與服務器之間傳遞參數用的一種方式 |
URL編碼須要先指定一種字符編碼,把字符串解碼後,獲得byte[],而後把小於0的字節+256,再轉換成16進制。前面再添加一個%。
* POST請求默認就使用URL編碼!tomcat會自動使用URL解碼!
* URL編碼:String username = URLEncoder.encode(username, "utf-8");
* URL解碼:String username = URLDecoder.decode(username, "utf-8");
|
這種場景下,編碼和解碼都是自動的,不須要手動干預
瀏覽器中顯示的"張三"
新建一個測試類 main方法中執行打印結果同樣
public static void main(String[] args) throws UnsupportedEncodingException {
String s= "張三";
System.out.println(URLEncoder.encode(s,"UTF-8"));
}