springweb開發中編碼亂碼問題解析

掘金小部隊發表於2017-10-20

因為平時開發過程中總遇到亂碼的問題,很煩惱,因此總結了一下,加深了自己的印象,有些粗糙,有不正確的地方歡迎指正。最有效的是自己擼碼模擬一下所有可能出現亂碼的情況。

為什麼會出現亂碼

一句話就能說明問題: 字元在儲存時的編碼格式如果和要顯示(解碼)時的編碼格式不一樣的話,就會出現亂碼問題。因此我們的前後端編碼一般都一致使用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.瀏覽器編碼

瀏覽器編碼的設定和頁面編碼不一致會導致頁面文字顯示亂碼

Jietu20171013-001221.jpg-303.2kB
Jietu20171013-001221.jpg-303.2kB

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…

參考:深入分析 web 請求響應中的編碼問題

相關文章