因為平時開發過程中總遇到亂碼的問題,很煩惱,因此總結了一下,加深了自己的印象,有些粗糙,有不正確的地方歡迎指正。最有效的是自己擼碼模擬一下所有可能出現亂碼的情況。
為什麼會出現亂碼
一句話就能說明問題: 字元在儲存時的編碼格式如果和要顯示(解碼)時的編碼格式不一樣的話,就會出現亂碼問題。因此我們的前後端編碼一般都一致使用UTF-8.
幾種亂碼解析
- "??"亂碼分析:
ISO-8859-1 僅能編碼非英文字元,所以非英文字元被其編碼時會被轉換為 0x3F(即?的 ASCII 編碼,也是 UTF-8 編碼),這時編碼已經真被轉成不可逆的亂碼了。之後無論用相容 ASCII 的哪種編碼方案解碼還原出的字串都是"?"。 - "²âÊÔ"亂碼分析:
ISO-8859-1 僅能表示非英文字元,所以使用其解碼時會嚴格按一個位元組一個位元組地進行解析(這種操作其實對編碼沒構成破壞,還可以重新用 ISO-8859-1 獲取位元組流後再用正確的編碼方式解碼得到正確的字串)。 - "����"亂碼分析:
用 UTF-8 解碼經 GB18030 編碼的位元組流時發現四個位元組均為 UTF-8 非法位元組流,所以直接轉化為了�。
決定編碼的因素
一個http請求經過的環節:
瀏覽器--->伺服器---->瀏覽器
在這個環節中每一步都會有影響編碼的因素:
1.頁面編碼
HTML meta data 中的 charset
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>hello</title>
</head>複製程式碼
2.瀏覽器編碼
瀏覽器編碼的設定和頁面編碼不一致會導致頁面文字顯示亂碼
3.ajax請求
ajaxGet
AjaxGet中的查詢引數會受瀏覽器編碼影響,所以最好使用 encodeURI 或 encodeURIComponent 手動顯式地將整個 URL 或者查詢字串按 UTF-8 編碼。
ajaxPost
ajaxPost 請求時對於 URI 和請求體都是預設按 utf-8 編碼,而不受 content type 影響。 所以 ajaxPost 不亂碼的必要條件是將服務端 request 中的 characterEncoding 設為"utf-8"。
4.spring編碼
通過類org.springframework.web.filter.CharacterEncodingFilter,定義request和response的編碼。這是因為在spring原始碼裡預設用的是ISO-8859-1,對中文支援不好,因此這裡配置成UTF-8.
在web.xml裡配置
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>複製程式碼
CharacterEncodingFilter類具有encoding和forceEncoding兩個屬性,其中encoding是表示設定request的編碼,forceEncoding表示是否同時設定response的編碼。
5.tomcat配置
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8" />複製程式碼
Tomcat的conf裡的server.xml裡的配置,一般配置成UTF-8,也有配置成ISO-8859-1,這裡的配置在發起get請求時會對uri進行編碼,因此需要進行處理,不然會出現亂碼。但是對post請求的body不會產生影響。
解決方法:
$.ajax({
url:"/hello?param=" + encodeURI(encodeURI($("#before").html())),
type:"GET",
contentType:"application/x-www-form-urlencoded; charset=utf-8",
success:function(result){
$("#after").val(result);
}
});複製程式碼
對get請求的url裡的引數進行兩次encodeURI;
@RequestMapping(value = "/hello",method = RequestMethod.GET,produces = "text/plain;charset=UTF-8")
@ResponseBody
public String index(@RequestParam("param") String param) throws UnsupportedEncodingException {
String newParam = URLDecoder.decode(param,"utf-8");
String handleMsg = "後臺處理後資料:";
String result = handleMsg + newParam;
return result;
}複製程式碼
後臺獲取引數時進行一次解碼,這樣獲取到的引數就不會出現亂碼。
程式碼地址:github.com/PanPanda/en…