客戶端編碼與伺服器解碼全過程
做java的web開發有段日子了,有個問題老是困擾著我,就是亂碼問題,基本上是網上查詢解決方案(網上資料真的很多),都是一大堆的介紹如何解決此類的亂碼問題,但是沒幾個把問題的來龍去脈說清楚的,有時候看了些文章後,以為自己懂了,但是在開發中亂碼問題又像鬼魂一樣出來嚇人,真是頭大了!這篇文章是我長時間和亂碼做鬥爭的一些理解的積累,還希望有更多的朋友給出指點和補充。
form有2中方法把資料提交給伺服器,get和post,分別說下吧。
(一)get提交
1.首先說下客戶端(瀏覽器)的form表單用get方法是如何將資料編碼後提交給伺服器端的吧。
對於get方法來說,都是把資料串聯在請求的url後面作為引數,如:http://localhost:8080/servlet?msg=abc
(很常見的一個亂碼問題就要出現了,如果url中出現中文或其它特殊字元的話,如:http://localhost:8080/servlet?msg=杭州,伺服器端容易得到亂碼),url拼接完成後,瀏覽器會對url進行URL encode,然後傳送給伺服器,URL encode的過程就是把部分url做為字元,按照某種編碼方式(如:utf-8,gbk等)編碼成二進位制的位元組碼,然後每個位元組用一個包含3個字元的字串 "%xy" 表示,其中xy為該位元組的兩位十六進位制表示形式。我這裡說的可能不清楚,具體介紹可以看下java.net.URLEncoder類的介紹在
2。伺服器端(tomcat)是如何將資料獲取到進行解碼的。
第一步是先把資料用iso-8859-1進行解碼,對於get方法來說,tomcat獲取資料的是ASCII範圍內的請求頭字元,其中的請求url裡面帶有引數資料,如果引數中有中文等特殊字元,那麼目前還是URL encode後的%XY狀態,先停下,我們先說下開發人員一般獲取資料的過程。通常大家都是request.getParameter("name")獲取引數資料,我們在request物件或得的資料都是經過解碼過的,而解碼過程中程式裡是無法指定,這裡要說下,有很多新手說用request.setCharacterEncoding("字符集")可以指定解碼方式,其實是不可以的,看servlet的官方API說明有對此方法的解釋:Overrides the name of the character encoding used in the body of this request. This method must be called prior to reading request parameters or reading input using getReader().可以看出對於get方法他是無能為力的。那麼到底用什麼編碼方式解碼資料的呢,這是tomcat的事情了,預設預設用的是iso-8859-1,這樣我們就能找到為什麼get請求帶中文引數為什麼在伺服器端得到亂碼了,原因是在客戶端一般都是用UTF-8或GBK對資料URL encode,這裡用iso-8859-1方式URL decoder顯然不行,在程式裡我們可以直接
- new String(request.getParameter("name").getBytes("iso-8859-1"),"客戶端指定的URL encode編碼方式")
new String(request.getParameter("name").getBytes("iso-8859-1"),"客戶端指定的URL encode編碼方式")
還原回字節碼,然後用正確的方式解碼資料,網上的文章通常是在tomcat裡面做個配置
- <Connectorport="8080"protocol="HTTP/1.1"maxThreads="150"connectionTimeout
這樣是讓tomcat在獲取資料後用指定的方式URL decoder,URL decoder的介紹在這裡
(一)post提交
1.客戶端(瀏覽器)的form表單用post方法是如何將資料編碼後提交給伺服器端的。
在post方法裡所要傳送的資料也要URL encode,那麼他是用什麼編碼方式的呢?
在form所在的html檔案裡如果有段<meta http-equiv="Content-Type" content="text/html; charset=字符集(GBK,utf-8等)"/>,那麼post就會用此處指定的編碼方式編碼。一般大家都認為這段程式碼是為了讓瀏覽器知道用什麼字符集來對網頁解釋,所以網站都會把它放在html程式碼的最前端,儘量不出現亂碼,其實它還有個作用就是指定form表單的post方法提交資料的URL encode編碼方式。從這裡可以看出對於get方法來數,瀏覽器對資料的URL encode的編碼方式是有瀏覽器設定來決定,(可以用js做統一指定),而post方法,開發人員可以指定。
2。伺服器端(tomcat)是如何將資料獲取到進行解碼的。
如果用tomcat預設預設設定,也沒做過濾器等編碼設定,那麼他也是用iso-8859-1解碼的,但是request.setCharacterEncoding("字符集")可以派上用場。
我發現上面說的tomcat所做的事情前提都是在請求頭裡沒有指定編碼方式,如果請求頭裡指定了編碼方式將按照這種方式編碼。
有2篇文章推薦下,地址分別是
http://www.cnblogs.com/yencain/articles/1321386.html;
http://wanghuan8086.javaeye.com/blog/173869