linux servlet 乱码问题,Servlet一次乱码排查后的总结
由來
在寫一個(gè)小小的表單提交功能的時(shí)候,出現(xiàn)了亂碼,很奇怪request上來的參數(shù)全部是亂碼,而從數(shù)據(jù)庫查詢出來的中文顯示到頁面正常,鎖定肯定是request對(duì)象那里出了問題。后來經(jīng)過排查,發(fā)現(xiàn)是我封裝的框架中出了問題,總結(jié)為在setCharacterEncoding方法之前,調(diào)用了getParameter方法,導(dǎo)致字符集改變失敗。沒看過Tomcat實(shí)現(xiàn)Servlet的源碼,貌似是一旦調(diào)用getParameter方法Request的參數(shù)就會(huì)全部被解析,從而再調(diào)用setCharacterEncoding就無效了。
原理解析
其實(shí)編碼問題本質(zhì)還是兩點(diǎn):
瀏覽器在封裝Http請(qǐng)求的時(shí)候的編碼和服務(wù)器在解析Http請(qǐng)求編碼不一致
服務(wù)器返回?cái)?shù)據(jù)的時(shí)候編碼和瀏覽器解析不同。
那么我們就從這兩點(diǎn)入手解析。
瀏覽器請(qǐng)求
在點(diǎn)擊提交表單的那一刻,瀏覽器把表單內(nèi)容封裝成一個(gè)Http請(qǐng)求,數(shù)據(jù)通過a=1&b=2這樣的形式直接請(qǐng)求服務(wù)器,表單值會(huì)被瀏覽器最一次urlencode,對(duì)于不同的請(qǐng)求方式編碼不同:
Get和Post請(qǐng)求
瀏覽器會(huì)讀取頁面的編碼(頁面編碼會(huì)在Content-type頭中體現(xiàn)),用此編碼對(duì)表單值做urlencode,那么到服務(wù)器的編碼方式就是你Content-Type里的編碼。很多通過JS提交表單為了規(guī)避瀏覽器的urlencode帶來的編碼混淆,會(huì)對(duì)數(shù)據(jù)首先做一次urlencode,這樣在服務(wù)器上做一次urldecode既可(因?yàn)閖s做完urlencode后內(nèi)容為ASCII字符,所以這樣的字符無論瀏覽器用什么編碼解碼出來都是一樣的)
AJAX請(qǐng)求
在Jquery中AJAX請(qǐng)求全部使用utf8編碼封裝請(qǐng)求,如果你的頁面和項(xiàng)目用的非utf8編碼,一定會(huì)出現(xiàn)亂碼
瀏覽器地址欄直接輸入帶參數(shù)的地址
這種情況就比較復(fù)雜,不同的瀏覽器編碼也不相同。Chrome之類的瀏覽器默認(rèn)使用utf8編碼(urlencode),而IE則使用GBK(死變態(tài)IE!!!)。
服務(wù)器端解碼
對(duì)于服務(wù)器端我在此只討論Servlet。
Get請(qǐng)求
對(duì)于Get請(qǐng)求,有兩種方式解碼:
在Servlet容器中設(shè)置,例如Tomcat設(shè)置URIEncoding="UTF-8",就會(huì)對(duì)Get請(qǐng)求用utf8解碼(貌似Tomcat7會(huì)報(bào)無效,具體解決請(qǐng)百度,反正我不同這種方法)
String name = new String(request.getParameter("name").getBytes("iso-8859-1"),"GBK"));第一個(gè)編碼就是你Servlet容器(例如Tomcat)里設(shè)置的編碼,默認(rèn)iso-8859-1,第二個(gè)參數(shù)就是你瀏覽器使用的編碼格式。如果你用表單提交,那這個(gè)編碼就是頁面的編碼(Content-Type里的charset=XXX),如果你直接用瀏覽器地址欄里敲,恭喜你,你得判斷userAgent來使用不同編碼了。這也是我為啥不提倡第一種方式,因?yàn)樗龅綖g覽器直接敲出來的參數(shù)就非常不靈活。
至于為什么要使用getBytes("iso-8859-1"),是因?yàn)樵谀銥g覽器用某種編碼后,Servlet容器自作多情給你用iso-8859-1解碼了一下,如果你設(shè)置了URIEncoding="UTF-8"它就會(huì)用utf8給你解碼,運(yùn)氣好你瀏覽器用的也是這種編碼,那解出來就直接用了,所以在ISO-8859-1的情況下你得再“原路返回”到二進(jìn)制,重新用正確的編碼解碼一下。
Post請(qǐng)求和Ajax請(qǐng)求
Post請(qǐng)求就比較簡單一點(diǎn)了,同樣你可以使用Get請(qǐng)求中的方法2來解決,不過比較麻煩,這時(shí)候我們就可以使用Servlet里的方法request.setCharacterEncoding方法設(shè)置你的解碼類型,例如你的頁面編碼是utf8,表單則urlencode成utf8了,那么你在調(diào)用getParameter方法之前(記住,一定要之前!!在第一次調(diào)用getParameter之前!)使用setCharacterEncoding方法。 Ajax請(qǐng)求同理。
響應(yīng)請(qǐng)求
響應(yīng)也是相同道理,這回輪到服務(wù)器做編碼,瀏覽器做解碼。只需要設(shè)置response.setCharacterEncoding,就會(huì)自動(dòng)在響應(yīng)頭的Content-Type中加入charset=XXX,返回的內(nèi)容就可以被正常解析啦~
我想我說的相對(duì)比較清楚了,網(wǎng)上很多解決亂碼的帖子都只是講你加上某句代碼就會(huì)解決,這樣是不科學(xué)的,一定也要知道原理,也要知道每句代碼背后做了哪些工作。其實(shí)我們在操作HttpServlet對(duì)象的時(shí)候,本質(zhì)上是對(duì)Http頭的一些信息做修改。
如果有什么問題或者理解錯(cuò)誤的地方,歡迎指正討論。
總結(jié)
以上是生活随笔為你收集整理的linux servlet 乱码问题,Servlet一次乱码排查后的总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 01 LeNet-5论文笔记-Gradi
- 下一篇: 适配ofd签章SES_CertList