亂碼問題

一、js

      一般情況下, 發送 encodeURIComponent(parmeName)+"="+encodeURIComponent(parmeValue);
接收時, 直接 String paramValue = request.getParameter(paramName); // 容器自動解碼.
encodeURIComponent 使用的是 UTF-8 編碼規則來編的.
如果 request.getParameter(paramName) 時,容器也按 UTF-8 解的話,是正確的. 容器按什麼編碼來解碼,決定於 request.setCharacterEncoding(***) 或者 服務器程序配置.


爲什麼網上會有人提出在客戶端對字符串重複編碼兩次呢?
如果因爲項目需要,不能指定容器使用何種編碼規則來解碼提交的參數, 比如:需要接收來自不同頁面,不地編碼的參數內容時。 (又或者是開發人員被這有點複雜的東東搞得暈頭轉向,不懂得如何正確的去做好這接收參數的工作)
這個時候,在客戶端對參數進行二次編碼,可以有效的避開提交多字節字符”的這個棘手問題。
因爲第一次編碼,你的參數內容便不帶有多字節字符了,成了純粹的 Ascii 字符串。(這裏把編第一次的結果叫成 [STR_ENC1] 好了。[STR_ENC1] 是不帶有多字節字符的) 再編一次後,提交,接收時容器自動解一次 (容器自動解的這一次,不管是按 GBK 還是 UTF-8 還是 ISO-8859-1 都好,都能夠正確的得到 [STR_ENC1]) 然後,再在程序中實現一次 decodeURIComponent (Java中通常使用 java.net.URLDecoder(***, "UTF-8")) 就可以得到想提交的參數的原值。

二、瀏覽器端

     瀏覽器會給你編一次碼

     <form>提交時,瀏覽器使用什麼編碼編,決定於 form 的 accept-charset 屬性(標準瀏覽器) 或者 document.charset(IE)
<form accept-charset="...." >...</form> 提交 application/x-form-www-encoded 表單時,瀏覽器 把所有參數 按 key=value 的形式組合分別對 key, value 進行編碼. 多個參數間,用 "&" 連接

三、服務器端(容器層)

     Tomcat服務器會自動幫你做一次URLDecode

      在Tomcat的配置文件的Connector標籤中設置useBodyEncodingForURI或者URIEncoding屬性。
其中useBodyEncodingForURI參數表示是否用request.setCharacterEncoding參數對URL提交的數據和表單中GET方式提交的數據進行重新編碼,在默認情況下,該參數爲false(Tomcat4.0中該參數默認爲true);
URIEncoding參數指定對所有GET方式請求(包括URL提交的數據和表單中GET方式提交的數據)進行統一的重新編碼(解碼)的編碼。
URIEncoding和useBodyEncodingForURI區別是,URIEncoding是對所有GET方式的請求的數據進行統一的重新編碼(解碼),而useBodyEncodingForURI則是根據響應該請求的頁面的request.setCharacterEncoding參數對數據進行的重新編碼(解碼),不同的頁面可以有不同的重新編碼(解碼)的編碼。
所以對於URL提交的數據和表單中GET方式提交的數據,可以修改URIEncoding參數爲瀏覽器編碼或者修改useBodyEncodingForURI爲true,並且在獲得數據的JSP頁面中request.setCharacterEncoding參數設置成瀏覽器編碼

 

四、服務器端(代碼層)

在JAVA WEB開發中使用setCharacterEncoding()設置編碼

1、對於request,是指提交內容的編碼:
      指定後可以通過getParameter()則直接獲得正確的字符串,如果不指定,則默認使用iso8859-1編碼,需要進一步處理。參見下述"表單輸入"。值得注意的是在執行setCharacterEncoding()之前,不能執行任何getParameter()。java doc上說明:This method must be called prior to reading request parameters or reading input using getReader()。而且,該指定只對POST方法有效,對GET方法無效。分析原因,應該是在執行第一個getParameter()的時候,java將會按照編碼分析所有的提交內容,而後續的getParameter()不再進行分析,所以setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析所有的提交內容,setCharacterEncoding()自然就無效。

2、對於response,則是指定輸出內容的編碼:
     同時,該設置會傳遞給瀏覽器,告訴瀏覽器輸出內容所採用的編碼。
request.setCharacterEncoding()是設置從request中取得的值或從數據庫中取出的值 (只管post方式提交的問題///get需在server.xml中的:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"

URIEncoding="GBK" />

)加入URIEncoding="GBK",解決post和get之間亂碼問題


response.setContentType("text/html;charset=gb2312")是設置頁面中爲中文編碼

 

前者是設置動態文字(參數,數據庫),後者設置頁面靜態文字

response.setContentType指定 HTTP 響應的編碼,同時指定了瀏覽器顯示的編碼.
response.setCharacterEncoding設置HTTP 響應的編碼,如果之前使用response.setContentType設置了編碼格式,則使用response.setCharacterEncoding指定的編碼格式覆蓋之前的設置.與response.setContentType相同的是,調用此方法,必須在getWriter執行之前或者response被提交之前.

 

五、綜合

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類的介紹在這裏。瞭解了URL encode的過程,我們能看到2個很重要的問題,第一:需要URL encode的字符一般都是非ASCII的字符(籠統的講),再通俗的講就是除了英文字母以外的文字(如:中文,日文等)都要進行URL encode,所以對於我們來說,都是英文字母的url不會出現服務器得到亂碼問題,出現亂碼都是url裏面帶了中文或特殊字符造成的;第二:URL encode到底按照那種編碼方式對字符編碼?這裏就是瀏覽器的事情了,而且不同的瀏覽器有不同的做法,中文版的瀏覽器一般會默認的使用GBK,通過設置瀏覽器也可以使用UTF-8,可能不同的用戶就有不同的瀏覽器設置,也就造成不同的編碼方式,所以很多網站的做法都是先把url裏面的中文或特殊字符用javascript做URL encode,然後再拼接url提交數據,也就是替瀏覽器做了URL encode,好處就是網站可以統一get方法提交數據的編碼方式。 完成了URL encode,那麼現在的url就成了ASCII範圍內的字符了,然後以iso-8859-1的編碼方式轉換成二進制隨着請求頭一起發送出去。這裏想多說幾句的是,對於get方法來說,沒有請求實體,含有數據的url都在請求頭裏面,之所以用URL encode,我個人覺的原因是:對於請求頭來說最終都是要用iso-8859-1編碼方式編碼成二進制的101010.....的純數據在互聯網上傳送,如果直接將含有中文等特殊字符做iso-8859-1編碼會丟失信息,所以先做URL encode是有必要的。
   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顯然不行,在程序裏我們可以直接

Java代碼 複製代碼
  1. new String(request.getParameter("name").getBytes("iso-8859-1"),"客戶端指定的URL encode編碼方式")  
new String(request.getParameter("name").getBytes("iso-8859-1"),"客戶端指定的URL encode編碼方式")


還原回字節碼,然後用正確的方式解碼數據,網上的文章通常是在tomcat裏面做個配置

Xml代碼 複製代碼
  1. <Connector port="8080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000" redirectPort="8443" URIEncoding="GBK"/>  


這樣是讓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所做的事情前提都是在請求頭裏沒有指定編碼方式,如果請求頭裏指定了編碼方式將按照這種方式編碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章