解析訪問JSP一系列的編碼解碼過程-詳細
出自:http://japi.javaeye.com/blog/288779
亂碼是個讓人頭痛的問題...
頁面的亂碼,servlet中的亂碼,資料庫的亂碼....
一個煩字了得..
解決的方法也很早就出來...不多講...
先看看兩個網址:
http://www.google.cn/search?client=aff-cs-worldbrowser&forid=1&ie=utf-8&oe=UTF-8&hl=zh-CN&q=開源
http://www.javaeye.com/search?type=all&query=分頁
點擊看看什麼效果..選中URL,再斷行符號看看...
--------------------------------------------------------
說說從URL到servlet再到頁面的一系列編碼解碼過程..
首Crowdsourced Security Testing道在JAVA中的字元都是使用unicode
其次,我們假定在頁面中使用了utf-8編碼,當然你還可以使用gb2312之類的...但強烈建議你使用utf-8
1.輸入URL...
此時,servlet引擎就做些事..
把URL進行編碼,按照ISO8859-1字元集編碼進行轉換成UNICODE,再封裝到ServletRequest對象中.
當我們使用表單的時候,post,get方式,會以頁面的字元編碼對錶單中的內容進行,編碼.這個過程有點像URLEncoder.encode()方法的效果...
2.得到URL中的參數..
這是我們常做的,一個方法而已嘛..request.getParameter("paramName")
這個方法的背後還有一些解碼工作..
亂碼的原因有時就在此..
getParamter方法,對URL進行解碼,在servlet規範中沒有明確規定解碼所採用的字元集編碼,它由各個servlet引擎廠商自行決定...tomcat中預設採用ISO8859-1字元集進行URL解碼.
對於post方式:可以使用request.setCharacterEncoding(),方法指定別的解碼方式.
對於get方式:
可以使用原始的方法new String(param.getBytes("iso8859-1"),"utf-8")
這條語句在這兒的作用:
把getParameter方法解碼成的錯誤unicode還原成正確的編碼.
怎麼講呢?這兒解釋有點麻煩..
在頁面中提交表單的時候,表單內容使用頁面字元碼utf-8編碼,而getParameter預設的方法是以iso8859-1解碼的,所以如果你不處理下,就會是亂碼了...
ISO8859-1與unicode之間的轉換是無損的..
我們使用getBytes("iso8859-1")還原成正確的字元數組,再以utf-8編碼,就得到正確的結果了..
這個過程是這樣的:
(以utf-8編碼) getParameter以(ios8859-1)解碼
URL--------------->字元數組------------------------------>UNICODE(錯誤)
使用getBytes("iso8859-1")還原 new String(bytes,"utf-8")
UNICODE------------------------>字元數組--------------->UNICODE(正確)-
也可以修改server.xml
Java代碼
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443" <span style="color: red;">URIEncoding="utf-8</span>"/>
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/>
讓url解碼時使用utf-8.
記得上面讓做實驗嗎...選中URL,斷行符號.此時,URL中的中文字元是以本地符編碼的.就是GB2312編碼..
像javaeye的.URL中的是GB2312,而在幕後處理的時候以使用的utf-8,所以就出現了亂碼..google的那個,
參數中有個ie,那可能就是瀏覽器的編碼,如果改成gb2312就不會出現亂碼...在這個方面.google比baidu做得優秀..頁面的編碼也會根
據這個參數來確定,..而baidu只是對gb2312處理了..所以從這點看,baidu還是沒有走向國際化..你可以再做實驗驗證下..
直接在輸入URL,過程也一樣
先對URL編碼,以ISO8859-1編碼,getParameter解碼..GB2312---->UNICODE
3,頁面得到字元.
在servlet中,都是unicode的編碼,會以request.setCharacter()編碼成字元數組.
在頁面中顯示時,再以contentType屬性解碼一下..所有這兩處得一致.!
----------------------
以上就是其中的一些過程,還有一些細節...
比如在servlet中沒有使用setCharacterEncoding方法,也沒有使用相應的filter處理,
那麼如果有URL的參數的時候,顯示得使用URLEncoder.encode()編碼下..在頁面上的URL中才會正確顯示..
對於編碼和解碼,都是對稱的...底層都是使用位元組數組來傳遞,我們只要知道了這個位元組數組是怎麼得到的就知道怎麼去處理,也知道亂碼原因在哪一步...
比如輸入URL,URL中的是GB2312,先是URL編碼,GB2312以ISO8859-1---->位元組數組..getParameter又
以ISO8859-1對位元組數組解碼,此時,你寫上new
String(p.getBytes("iso8859-1"),"utf-8")就是亂碼...
寫p.getBytes("iso8859-1"),"gb2312"就是正確的..
在搜尋分頁的時候,下一頁帶的中文參數,一般都會在頁面上顯示得對它進行URLEncoder.encode,如果沒有,就得在servlet中進行重新解碼..也就是getBytes一下..
1.在頁面中不顯示encode,那麼在servlet中使用getBytes,重新編碼.
這是因為:URL中的UTF-8字元------(ISO8859-1)-------->字元數組-------getParameter以
iso8859-1解碼--------->unicode,這裡的UNICODE是不正確的,它是UTF-8編碼的.
2.在頁面中顯示encode下,這個過程也可以在servlet中進行,encode(key,"utf-8"),在servlet中不要進行
request.setCharacter(),也就是在servlet中只有iso8859-1與UNICODE間的轉換...到頁面的時候才涉及到本
地符...
-------------------------------------------
關鍵點:對稱的轉換...底層位元組數組的編碼類別型..