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請求的。這下關於編碼使用的就相對完整了。
最後感謝一下參考博客,謝謝您們的分享:
http://blog.csdn.net/superch0054/article/details/9325793