1. 程式人生 > >Web開發過程中亂碼問題

Web開發過程中亂碼問題

Springmvc、get/post提交亂碼

淡泊以明志,寧靜以致遠

昨天在用springmvc開發Web專案時,遇到了亂碼問題,弄了將近5個小時才弄好。希望我遇到的問題可以幫助到大家。
【問題描述】我在JSP頁面通過超連結訪問Controller,請求的地址中有中文,例如

<a href="http://localhost:8080/mydemo/user/save?uname='中'">連結</a>

但是到達Controller中取出來確實亂碼。為什麼會產生亂碼呢?怎樣處理這樣的亂碼呢?在徹底解決這個問題之前,我們需要對編碼、解碼的基礎知識有一定的瞭解。這就是所謂的“工欲善其事,必先利其器”。

一、編碼的基礎知識

(一)為什麼要編碼?

我們和瀏覽器互動使用的是字元,我們傳送給伺服器的請求在網路間是通過位元組流傳輸的。所以,我們傳送的請求要結果編碼,伺服器接收到請求後要進行解碼。

(二)什麼是編碼和解碼?

這裡寫圖片描述
上面就是編碼、解碼和字符集的基礎概念。編碼有兩種方式:第一種就是通過字符集進行編碼和解碼;第二種就是URI編碼、URI解碼
當然在進行URI編碼時,也要有對應的字符集。比如,“中”通過URI編碼後的結果是“%E4%B8%AD%”。這裡同樣使用了utf-8字符集。(”中”的urf-8編碼是”E4B8AD”)很容易看出來,URI編碼就是將一個字串用%+對應的字符集編碼

組織的字串來表示的。

(三)URI編碼(理解重點)

什麼時候會進行URI編碼呢?URI編碼會對我們傳送請求的地址進行編碼。例如上面。

<a href="http://localhost:8080/mydemo/user/save?uname='中'">連結</a>

URI會對後面請求的地址進行編碼。預設是由瀏覽器進行的。不同的瀏覽器,在不同的作業系統中在進行URI編碼時,採用的字符集不同。所以,我們的解決方案是在頁面先通過JavaScript中的URLEncode函式對中文先進行URI編碼,這樣我們就可以指定字元集了。然後把編好碼的結果放到地址中,進行請求。
但是,我遇到的問題並不是這個問題。因為如果我們不手動進行URI編碼,瀏覽器也會根據網頁中的charset中指定的字符集進行編碼。

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page contentType="text/html;charset=utf-8"%>

(四)從頁碼請求到伺服器接收請求後流程圖

①原URL(請求地址)
②Get提交,瀏覽器根據http頭的Content-Type的charset對URL進行URI編碼

<%@ page contentType="text/html;charset=utf-8"%>

Post提交,瀏覽器根據http頭的

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

對URL進行URI編碼。
或者利用Javascript使用指定字符集手動對URL進行編碼。
④編碼後的URL全是ASCII碼。
⑤然後瀏覽器把URL以iso-8859-1編碼方式轉換成二進位制的位元組碼,進行網路傳輸。這裡有個理解重點:iso-8859-1中是沒有中文的。
⑥隨請求頭一起傳送出去(get無實體,post有實體)
⑦伺服器接收到瀏覽器傳送過來的URL,並用iso-8859-1進行解碼
⑧網頁一般都會有meta頭的charset選項,伺服器根據此進行再次解碼(post表單提交過來的也會根據此編碼進行解碼)。但是這個只使用於post方式提交的請求。
⑨最後就得到正確的值。

然而到達這裡問題似乎還是沒有解決,不過問題的原因可以推測出來了。問題就是iso-8859-1中是沒有中文的。通過get方式提交的請求,URL還是會根據伺服器預設的iso-8859-1進行解碼,沒有對應的中文解碼,所以產生了亂碼。

(五)URIEncoding和useBodyEncodingForURI

在我開發過程中用的是Tomcat 6x,所以我又去了解了一下Tomcat對Get的URL解碼相關知識。
Tomcat預設是按iso-8859-1進行URL解析,而iso-8859-1中沒有中文,所以產生亂碼,這裡剛才分析過了。
常見的解決方式是:在tomcat的server.xml下的connetor屬性中增加URIEncoding或者useBodyEncodingForURI屬性。
按照tomcat-docs/config/http.html文件的說明
**URIEncoding:**This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
**useBodyEncodingForURI:**This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding.

也就是說,
useBodyEncodingForURI引數表示是否用request.setCharacterEncoding引數對URL提交的資料和表單中GET方式提交的資料進行重新編碼,在預設情況下,該引數為false。
URIEncoding引數指定對所有GET方式請求進行統一的重新編碼(解碼)的編碼。
URIEncoding和useBodyEncodingForURI區別是,URIEncoding是對所有GET方式的請求的資料進行統一的重新編碼,而useBodyEncodingForURI則是根據響應該請求的頁面的request.setCharacterEncoding引數對資料進行的重新編碼,不同的頁面可以有不同的重新編碼的編碼。

所以,最終的解決方案就出來咯。在tomcat的server.xml下的connetor屬性中增加URIEncoding屬性。
這裡寫圖片描述

最後,補充一個相關的知識點:
大家都知道,我們在使用springmvc進行Web專案開發時,會在web.xml中配置字元編碼過濾器。

<filter>
    <filter-name>encodingFilter</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>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

但是這個配置是針對post請求的。這下關於編碼使用的就相對完整了。