form表单提交数据编码方式和tomcat接受数据解码方式
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
簡(jiǎn)單介紹亂碼和http請(qǐng)求
1) ?亂碼問題是web開發(fā)過程中經(jīng)常遇到的問題,主要原因就是URL中使用了非ASCII碼造成服務(wù)器后臺(tái)程序解析出現(xiàn)亂碼的問題。
2) ?URL中最容易出現(xiàn)中文的地方就是在QueryString的參數(shù)值還有Servletpath中。
3) ?簡(jiǎn)單用一個(gè)圖來說明一下http請(qǐng)求的流程:
第一步:瀏覽器把URL經(jīng)過編碼送給服務(wù)器;(get請(qǐng)求根據(jù)瀏覽器設(shè)置的編碼,get默認(rèn)的是ISO-8859-1;??post根據(jù)頁面設(shè)置的編碼)
第二步:服務(wù)器(tomcat)把這些請(qǐng)求解碼處理完畢之后將顯示的內(nèi)容進(jìn)行編碼發(fā)送給客戶端瀏覽器;
第三步:瀏覽器按照指定的編碼顯示網(wǎng)頁
?
form有2中方法把數(shù)據(jù)提交給服務(wù)器,get和post,分別說下吧。?
- get提交?
??1. 首先說下客戶端(瀏覽器)的form表單用get方法是如何將數(shù)據(jù)編碼后提交給服務(wù)器端的吧。?
???
????對(duì)于get方法來說,都是把數(shù)據(jù)串聯(lián)在請(qǐng)求的url后面作為參數(shù),如:http://localhost:8080/servlet?msg=abc?
(很常見的一個(gè)亂碼問題就要出現(xiàn)了,如果url中出現(xiàn)中文或其它特殊字符的話,如:http://localhost:8080/servlet?msg=杭州,服務(wù)器端容易得到亂碼),url拼接完成后,瀏覽器會(huì)對(duì)url進(jìn)行URL encode,然后發(fā)送給服務(wù)器,URL encode的過程就是把部分url做為字符,按照某種編碼方式(如:utf-8,gbk等)編碼成二進(jìn)制的字節(jié)碼,然后每個(gè)字節(jié)用一個(gè)包含3個(gè)字符的字符串 "%xy" 表示,其中xy為該字節(jié)的兩位十六進(jìn)制表示形式。具體介紹可以看下java.net.URLEncoder類的介紹在這里。
了解了URL encode的過程,我們能看到2個(gè)很重要的問題,
- 需要URL encode的字符一般都是非ASCII的字符(籠統(tǒng)的講),再通俗的講就是除了英文字母以外的文字(如:中文,日文等)都要進(jìn)行URL encode,所以對(duì)于我們來說,都是英文字母的url不會(huì)出現(xiàn)服務(wù)器得到亂碼問題,出現(xiàn)亂碼都是url里面帶了中文或特殊字符造成的;
- URL encode到底按照那種編碼方式對(duì)字符編碼?這里就是瀏覽器的事情了,而且不同的瀏覽器有不同的做法,中文版的瀏覽器一般會(huì)默認(rèn)的使用GBK,通過設(shè)置瀏覽器也可以使用UTF-8,可能不同的用戶就有不同的瀏覽器設(shè)置,也就造成不同的編碼方式,所以很多網(wǎng)站的做法都是先把url里面的中文或特殊字符用javascript做URL encode,然后再拼接url提交數(shù)據(jù),也就是替瀏覽器做了URL encode,好處就是網(wǎng)站可以統(tǒng)一get方法提交數(shù)據(jù)的編碼方式。 完成了URL encode,那么現(xiàn)在的url就成了ASCII范圍內(nèi)的字符了,然后以iso-8859-1的編碼方式轉(zhuǎn)換成二進(jìn)制隨著請(qǐng)求頭一起發(fā)送出去。這里想多說幾句的是,對(duì)于get方法來說,沒有請(qǐng)求實(shí)體,含有數(shù)據(jù)的url都在請(qǐng)求頭里面。
???2. 服務(wù)器端(tomcat)是如何將數(shù)據(jù)獲取到進(jìn)行解碼的。?
???第一步是先把數(shù)據(jù)用iso-8859-1進(jìn)行解碼,對(duì)于get方法來說,tomcat獲取數(shù)據(jù)的是ASCII范圍內(nèi)的請(qǐng)求頭字符,其中的請(qǐng)求url里面帶有參數(shù)數(shù)據(jù),如果參數(shù)中有中文等特殊字符,那么目前還是URL encode后的%XY狀態(tài),先停下,我們先說下開發(fā)人員一般獲取數(shù)據(jù)的過程。通常大家都是request.getParameter("name")獲取參數(shù)數(shù)據(jù),我們?cè)趓equest對(duì)象或得的數(shù)據(jù)都是經(jīng)過解碼過的,而解碼過程中程序里是無法指定,這里要說下,有很多新手說用request.setCharacterEncoding("字符集")可以指定解碼方式,其實(shí)是不可以的,看servlet的官方API說明有對(duì)此方法的解釋: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().可以看出對(duì)于get方法他是無能為力的,因?yàn)間et請(qǐng)求的數(shù)據(jù)在請(qǐng)求頭部,而request.setCharacterEncoding作用于請(qǐng)求報(bào)文主體。那么到底用什么編碼方式解碼數(shù)據(jù)的呢,這是tomcat的事情了,默認(rèn)缺省用的是iso-8859-1,這樣我們就能找到為什么get請(qǐng)求帶中文參數(shù)為什么在服務(wù)器端得到亂碼了,原因是在客戶端一般都是用UTF-8或GBK對(duì)數(shù)據(jù)URL encode,這里用iso-8859-1方式URL decoder顯然不行,在程序里我們可以直接?
Java代碼 ?
new?String(request.getParameter("name").getBytes("iso-8859-1"),"客戶端指定的URL?encode編碼方式")??還原回字節(jié)碼,然后用正確的方式解碼數(shù)據(jù)。
?
PS:
網(wǎng)上的文章通常是在tomcat里面做個(gè)配置?
Xml代碼 ?
<Connector?port="8080"?protocol="HTTP/1.1"?maxThreads="150"?connectionTimeout="20000"redirectPort="8443"?URIEncoding="GBK"/>??
這樣是讓tomcat在獲取數(shù)據(jù)后用指定的方式URL decoder,這樣配置以后我們就不需要在代碼里解碼了。
?
- post提交?
1.客戶端(瀏覽器)的form表單用post方法是如何將數(shù)據(jù)編碼后提交給服務(wù)器端的。?
在post方法里所要傳送的數(shù)據(jù)也要URL encode,那么他是用什么編碼方式的呢??在form所在的html文件里如果有如下代碼,
那么post就會(huì)用此處指定的編碼方式編碼。其中pageEncoding用來告訴tomcat此文件所用的字符編碼。這個(gè)編碼應(yīng)該與eclipse保存文件用的編碼一致。Tomcat以此編碼方式來讀取JSP文件并編譯。page標(biāo)簽中的contentType用來設(shè)置tomcat往瀏覽器發(fā)送HTML內(nèi)容所使用的編碼。這個(gè)編碼會(huì)在HTTP響應(yīng)頭中指定以通知瀏覽器。
一般大家都認(rèn)為這段代碼是為了讓瀏覽器知道用什么字符集來對(duì)網(wǎng)頁解釋,所以網(wǎng)站都會(huì)把它放在html代碼的最前端,盡量不出現(xiàn)亂碼,其實(shí)它還有個(gè)作用就是指定form表單的post方法提交數(shù)據(jù)的URL encode編碼方式。從這里可以看出對(duì)于get方法來數(shù),瀏覽器對(duì)數(shù)據(jù)的URL encode的編碼方式是有瀏覽器設(shè)置來決定,(可以用js做統(tǒng)一指定),而post方法,開發(fā)人員可以指定。?
2。服務(wù)器端(tomcat)是如何將數(shù)據(jù)獲取到進(jìn)行解碼的。?
如果用tomcat默認(rèn)缺省設(shè)置,也沒做過濾器等編碼設(shè)置,那么他也是用iso-8859-1解碼的,但是request.setCharacterEncoding("字符集")可以派上用場(chǎng)。?
我發(fā)現(xiàn)上面說的tomcat所做的事情前提都是在請(qǐng)求頭里沒有指定編碼方式,如果請(qǐng)求頭里指定了編碼方式將按照這種方式編碼。
?
- ?JAVA處理字符的原理
????JAVA使用UNICODE來存儲(chǔ)字符數(shù)據(jù),處理字符時(shí)通常有三個(gè)步驟:
????1、按指定的字符編碼形式,從源輸入流中讀取字符數(shù)據(jù)
????2、以UNICODE編碼形式將字符數(shù)據(jù)存儲(chǔ)在內(nèi)存中
????3、按指定的字符編碼形式,將字符數(shù)據(jù)編碼并寫入目的輸出流中
????所以JAVA處理字符時(shí)總是經(jīng)過了兩次編碼轉(zhuǎn)換,一次是從指定編碼轉(zhuǎn)換為UNICODE編碼,一次是從UNICODE編碼轉(zhuǎn)換為指定編碼。如果在讀入時(shí)用錯(cuò)誤的形式解碼字符,則內(nèi)存存儲(chǔ)的是錯(cuò)誤的UNICODE字符。而從最初文件中讀出的字符數(shù)據(jù),到最終在屏幕終端顯示這些字符,期間經(jīng)過了應(yīng)用程序的多次轉(zhuǎn)換。如果中間某次字符處理用錯(cuò)誤的編碼方式解碼了從輸入流讀取的字符數(shù)據(jù),或用錯(cuò)誤的編碼方式將字符寫入輸出流,則下一個(gè)字符數(shù)據(jù)的接收者就會(huì)編解碼出錯(cuò),從而導(dǎo)致最終顯示亂碼。這一點(diǎn),是我們分析字符編碼問題以及解決問題的指導(dǎo)思想。
?
一、在JAVA文件中硬編碼中文字符,在eclipse中運(yùn)行,控制臺(tái)輸出了亂碼。
????例如,我們?cè)贘AVA文件中寫入以下代碼:
????String text = "大家好";
????System.out.println(text);
????如果我們是在eclipse里編譯運(yùn)行,可能看到的結(jié)果是類似這樣的亂碼:????。那么,這是為什么呢?
????我們先來看看整個(gè)字符的轉(zhuǎn)換過程。
????1. 在eclipse窗口中輸入中文字符,并保存成UTF-8的JAVA文件。這里發(fā)生了多次字符編碼轉(zhuǎn)換。不過因?yàn)槲覀兿嘈舉clipse的正確性,所以我們不用分析其中的過程,只需要相信保存下的JAVA文件確實(shí)是UTF-8格式。
????2. 在eclipse中編譯運(yùn)行此JAVA文件。這里有必要詳細(xì)分析一下編譯和運(yùn)行時(shí)的字符編碼轉(zhuǎn)換。
????編譯:我們用javac編譯JAVA文件時(shí),javac不會(huì)智能到猜出你所要編譯的文件是什么編碼類型的,所以它需要指定讀取文件所用的編碼類型。默認(rèn)javac使用平臺(tái)缺省的字符編碼類型來解析JAVA文件。平臺(tái)缺省編碼是操作系統(tǒng)決定的,我們使用的是中文操作系統(tǒng),語言區(qū)域設(shè)置通常都是中國大陸,所以平臺(tái)缺省編碼類型通常是GBK。這個(gè)編碼類型我們可以在JAVA中使用System.getProperty("file.encoding")來查看。所以javac會(huì)默認(rèn)使用GBK來解析JAVA文件。如果我們要改變javac所用的編碼類型,就要加上-encoding參數(shù),如javac -encoding utf-8 Test.java。
????這里要另外提一下的是eclipse使用的是內(nèi)置的編譯器,并不能添加參數(shù),如果要為javac添加參數(shù)則建議使用ANT來編譯。不過這并非出現(xiàn)亂碼的原因,因?yàn)閑clipse可以為每個(gè)JAVA文件設(shè)置字符編碼類型,而內(nèi)置編譯器會(huì)根據(jù)此設(shè)置來編譯JAVA文件。
????運(yùn)行:編譯后字符數(shù)據(jù)會(huì)以UNICODE格式存入字節(jié)碼文件中。然后eclipse會(huì)調(diào)用java命令來運(yùn)行此字節(jié)碼文件。因?yàn)樽止?jié)碼中的字符總是UNICODE格式,所以java讀取字節(jié)碼文件并沒有編碼轉(zhuǎn)換過程。虛擬機(jī)讀取文件后,字符數(shù)據(jù)便以UNICODE格式存儲(chǔ)在內(nèi)存中了。
????3. 調(diào)用System.out.println來輸出字符。這里又發(fā)生了字符編碼轉(zhuǎn)換。
????System.out.println使用了PrintStream類來輸出字符數(shù)據(jù)至控制臺(tái)。PrintStream會(huì)使用平臺(tái)缺省的編碼方式來輸出字符。我們的中文系統(tǒng)上缺省方式為GBK,所以內(nèi)存中的UNICODE字符被轉(zhuǎn)碼成了GBK格式,并送到了操作系統(tǒng)的輸出服務(wù)中。因?yàn)槲覀儾僮飨到y(tǒng)是中文系統(tǒng),所以往終端顯示設(shè)備上打印字符時(shí)使用的也是GBK編碼。如果到這一步,我們的字符其實(shí)不再是GBK編碼的話,終端就會(huì)顯示出亂碼。那么,在eclipse運(yùn)行帶中文字符的JAVA文件,控制臺(tái)顯示了亂碼,是在哪一步轉(zhuǎn)換錯(cuò)誤呢?我們一步步來分析。
????保存JAVA文件成UTF-8后,如果再次打開你沒有看到亂碼,說明這步是正確的。
????用eclipse本身來編譯運(yùn)行JAVA文件,應(yīng)該沒有問題。
????System.out.println會(huì)把內(nèi)存中正確的UNICODE字符編碼成GBK,然后發(fā)到eclipse的控制臺(tái)去。
????等等,我們看到在Run Configuration對(duì)話框的Common標(biāo)簽里,控制臺(tái)的字符編碼被設(shè)置成了UTF-8!問題就在這里。??System.out.println已經(jīng)把字符編碼成了GBK,而控制臺(tái)仍然以UTF-8的格式讀取字符,自然會(huì)出現(xiàn)亂碼。將控制臺(tái)的字符編碼設(shè)置為GBK,亂碼問題解決。(這里補(bǔ)充一點(diǎn):eclipse的控制臺(tái)編碼是繼承了workspace的設(shè)置的,通常控制臺(tái)編碼里沒有GBK的選項(xiàng)而且不能輸入。我們可以先在 workspace的編碼設(shè)置中輸入GBK,然后在控制臺(tái)的設(shè)置中就可以看到GBK的選項(xiàng)了,設(shè)置好后再把workspace的字符編碼設(shè)置改回utf- 8就是。)
?
????二、JSP文件中硬編碼中文字符,在瀏覽器上顯示亂碼。
????我們用eclipse編寫一個(gè)JSP頁面,使用tomcat瀏覽這個(gè)頁面時(shí),整個(gè)頁面的中文字符都是亂碼。這是什么原因呢?
????JSP頁面從編寫到在瀏覽器上瀏覽,總共有四次字符編解碼。
????1. 以某種字符編碼保存JSP文件
????2. Tomcat以指定編碼來讀取JSP文件并編譯
????3. Tomcat向?yàn)g覽器以指定編碼來發(fā)送HTML內(nèi)容
????4. 瀏覽器以指定編碼解析HTML內(nèi)容
????這里的四次字符編解碼,有一次發(fā)生錯(cuò)誤最終顯示的就會(huì)是亂碼。我們依次來分析各次的字符編碼是如何設(shè)置的。
????保存JSP文件,這是在編輯器中設(shè)置的,比如eclipse中,設(shè)置文件字符類型為utf-8。
????JSP文件開頭的<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>,其中pageEncoding用來告訴tomcat此文件所用的字符編碼。這個(gè)編碼應(yīng)該與eclipse保存文件用的編碼一致。Tomcat以此編碼方式來讀取JSP文件并編譯。
????page標(biāo)簽中的contentType用來設(shè)置tomcat往瀏覽器發(fā)送HTML內(nèi)容所使用的編碼。這個(gè)編碼會(huì)在HTTP響應(yīng)頭中指定以通知瀏覽器。
????瀏覽器根據(jù)HTTP響應(yīng)頭中指定的字符編碼來解析HTML內(nèi)容。如:????
? HTTP/1.1 200 OKDate: Mon, 01 Sep 2008 23:13:31 GMTServer: Apache/2.2.4 (Win32) mod_jk/1.2.26Vary: Host,Accept-EncodingSet-Cookie: JAVA2000_STYLE_ID=1;Domain=www.java2000.net;Expires=Thu, 03-Nov-2011 09:00:10 GMT;Path=/Content-Encoding: gzipTransfer-Encoding: chunkedContent-Type: text/html;charset=UTF-8????另外,HTML中有個(gè)標(biāo)簽<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">中也指定了charset。不過這個(gè)字符編碼只有在當(dāng)網(wǎng)頁保存在本地作為靜態(tài)網(wǎng)頁時(shí)有效,因?yàn)闆]有HTTP頭,所以瀏覽器根據(jù)此標(biāo)簽來識(shí)別HTML內(nèi)容的編碼方式。
????現(xiàn)在在JSP文件中硬編碼出現(xiàn)亂碼的機(jī)會(huì)比較小了,因?yàn)榇蠹叶加昧巳鏴clipse的編輯器,基本上可以自動(dòng)保證這幾個(gè)編碼設(shè)置的正確性。現(xiàn)在更多碰到的是在JSP文件中從其他數(shù)據(jù)源中讀取中文字符所產(chǎn)生的亂碼問題。
?
?三、在JSP文件中讀取字符文件并在頁面中顯示,中文字符顯示為亂碼。
????比如,我們?cè)贘SP文件中使用以下代碼:
????<%
????BufferedReader reader = new BufferedReader(new FileReader("D://test.txt"));
????String content = reader.readLine();
????reader.close();
????%>
????<%=content%>
????test.txt里保存的是中文字符,但在瀏覽器上看到的亂碼。這是個(gè)經(jīng)常見到的問題。我們繼續(xù)用之前的方法一步步來分析輸入和輸出流
????1. test.txt是以某種編碼方式保存中文字符,比如UTF-8。
????2. BufferedReader直接讀取test.txt的字節(jié)內(nèi)容并以默認(rèn)方式構(gòu)造字符串。分析BufferedReader的代碼,我們可以看到 BufferedReader調(diào)用了FileReader的read方法,而FileReader又調(diào)用了FileInputStream的native 的read方法。所謂native的方法,就是操作系統(tǒng)底層方法。那么我們操作系統(tǒng)是中文系統(tǒng),所以FileInputStream默認(rèn)用GBK方式讀取文件。因?yàn)槲覀儽4鎡est.txt用的是UTF-8,所以在這里讀取文件內(nèi)容使用GBK是錯(cuò)誤的編碼。
????3. <%=content%>其實(shí)就是out.print(content),這里又用到了HTTP的輸出流JspWriter,于是字符串content又被以JSP的page標(biāo)簽中指定的UTF-8方式編碼成字節(jié)數(shù)組被發(fā)送到瀏覽器端。
????4. 瀏覽器以HTTP頭中指定的方式解碼字符,這時(shí)無論是用GBK還是UTF-8解碼,顯示的都是亂碼。
????可見,我們字符編碼轉(zhuǎn)換在第二步時(shí)出錯(cuò)了,UTF-8的字符串被當(dāng)做GBK讀入了內(nèi)存中。
????解決這個(gè)亂碼問題有兩種方法,一是把test.txt用GBK保存,則FileInputStream能正確讀入中文字符;二是使用InputStreamReader來轉(zhuǎn)換字符編碼,如:
????InputStreamReader sr = new InputStreamReader(new FileInputStream("D://test.txt"),"utf-8");
????BufferedReader reader = new BufferedReader(sr);
????這樣,JAVA就會(huì)用utf-8的方式來從文件中讀取字符數(shù)據(jù)。
????另外,我們可以通過在java命令后帶上Dfile.encoding參數(shù)來指定虛擬機(jī)讀取文件使用的默認(rèn)字符編碼,例如java -Dfile.encoding=utf-8 Test,
這樣,我們?cè)贘AVA代碼里用System.getProperty("file.encoding")取到的值為utf-8。
?
????四、JSP讀取request.getParameter里的中文參數(shù)后,在頁面顯示為亂碼。
????在JAVA的WEB應(yīng)用中,對(duì)request對(duì)象里的parameters的中文處理一直是常見也最難搞的一只大怪獸。經(jīng)常是剛搞定了這邊,那邊又出了亂碼。而導(dǎo)致這種復(fù)雜性的,主要是此過程中字符編解碼次數(shù)非常多,而且無論是瀏覽器還是WEB服務(wù)器特別是TOMCAT總是不能給我們一個(gè)比較滿意的支持。
????首先我們來分析用GET方式上傳參數(shù)的亂碼情況。
????例如我們?cè)跒g覽器地址欄輸入以下URL:http://localhost:8080/test/test.jsp?param=大家好
????我們的JSP代碼如此處理param這個(gè)參數(shù):
????<% String text = request.getParameter("param");??%>
????<%=text%>
????而就這么簡(jiǎn)單的兩句代碼,我們很有可能在頁面上看到這樣的亂碼:?ó????
????網(wǎng)上對(duì)處理request.getParamter中的亂碼有很多文章和方法,也都是正確的,只是方法太多讓人一直不明白到底是為什么。這里給大家分析一下到底是怎么一回事。
????首先,我們來看看與request對(duì)象有哪些相關(guān)的編碼設(shè)置:
????1. JSP文件的字符編碼
????2. 請(qǐng)求這個(gè)帶參數(shù)URL的源頁面的字符編碼
????3. IE的高級(jí)設(shè)置中的選項(xiàng)“總以u(píng)tf-8方式發(fā)送URL地址”
????4. TOMCAT的server.xml中配置URIEncoding
????5. 函數(shù)request.setCharacterEncoding()
????6. JS的encodeURIComponent函數(shù)與JAVA的URLDecoder類
????這么多條相關(guān)編碼設(shè)置,也難怪大家被搞得頭暈了。這里給大家根據(jù)各種情況給大家一一分析一下。見下表:
?以上表格里的現(xiàn)象,除了指名在IE7上,其他全是在IE6上測(cè)試的結(jié)果。
????由這個(gè)表我們可以看到,IE的“總以u(píng)tf-8方式發(fā)送URL地址”設(shè)置并不影響對(duì)parameter的解析,而從頁面請(qǐng)求URL和從地址欄輸入U(xiǎn)RL居然也有不同的表現(xiàn)。
????根據(jù)這個(gè)表列出的現(xiàn)象,大家只要用smartSniff抓幾個(gè)網(wǎng)絡(luò)包,并稍稍調(diào)查一下TOMCAT的源代碼,就可以得出以下結(jié)論:
????1. IE設(shè)置中的“總以u(píng)tf-8方式發(fā)送URL地址”只對(duì)URL的PATH部分起作用,對(duì)查詢字符串是不起作用的。也就是說,如果勾選了這個(gè)選項(xiàng),那么類似http://localhost:8080/test/大家好.jsp?param=大家好這種URL,前一個(gè)“大家好”將被轉(zhuǎn)化成utf-8形式,而后一個(gè)并沒有變化。這里所說的utf-8形式,其實(shí)應(yīng)該叫utf-8+escape形式。
????那么,查詢字符串中的中文字符,到底是用什么編碼傳送到服務(wù)器的呢?是系統(tǒng)默認(rèn)編碼,即GBK。也就是說,在我們中文操作系統(tǒng)上,傳送給WEB服務(wù)器的查詢字符串,總是以GBK來編碼的。
??2. 在頁面中通過鏈接或location重定向或open新窗口的方式來請(qǐng)求一個(gè)URL,這個(gè)URL里面的中文字符是用什么編碼的?是用該頁面的編碼類型。也就是說,如果我們從某個(gè)源JSP頁面上的鏈接來訪問http://localhost:8080/test/test.jsp?param=大家好這個(gè)URL,如果源JSP頁面的編碼是UTF-8,則大家好這幾個(gè)字的編碼就是UTF-8。
????而在地址欄上直接輸入U(xiǎn)RL地址,或者從系統(tǒng)剪貼板粘貼到地址欄上,這個(gè)輸入并非從頁面中發(fā)起的,而是由操作系統(tǒng)發(fā)起的,所以這個(gè)編碼只可能是系統(tǒng)的默認(rèn) 編碼,與任何頁面無關(guān)。我們還發(fā)現(xiàn),在不同的瀏覽器上,用鏈接方式打開的頁面,如果在地址欄上再敲個(gè)回車,顯示的結(jié)果也會(huì)不同。IE上敲回車后顯示不變 化,而傲游上可能就會(huì)有亂碼或亂碼消失的變化。說明IE上敲回車,實(shí)際發(fā)送的是之前記憶下來的內(nèi)存中的URL,而傲游上發(fā)送的從當(dāng)前地址欄重新獲取的 URL。
????3. TOMCAT的URIEncoding如果不加以設(shè)置,則默認(rèn)使用ISO-8859-1來解碼URL,設(shè)置后便用設(shè)置了的編碼方式來解碼。這個(gè)解碼同時(shí)包 括PATH部分和查詢字符串部分。可見,這個(gè)參數(shù)是對(duì)用GET方式傳遞的中文參數(shù)最關(guān)鍵的設(shè)置。不過,這個(gè)參數(shù)只對(duì)GET方式傳遞的參數(shù)有效,對(duì)POST 的無效。分析TOMCAT的源代碼我們可以看到,在請(qǐng)求一個(gè)頁面時(shí),TOMCAT會(huì)嘗試構(gòu)造一個(gè)Request對(duì)象,在這個(gè)對(duì)象里,會(huì)從 Server.xml里讀取URIEncoding的值,并賦值給Parameters類的queryStringEncoding變量,而這個(gè)變量將在 解析request.getParameter中的GET參數(shù)時(shí)用來指導(dǎo)字符解碼。
????4. request.setCharacterEncoding函數(shù)只對(duì)POST的參數(shù)有效,對(duì)GET的參數(shù)無效。且這個(gè)函數(shù)必須是在第一次調(diào)用 request.getParameter之前使用。這是因?yàn)镻arameters類有兩個(gè)字符編碼參數(shù),一個(gè)是encoding,另一個(gè)是 queryStringEncoding,而setCharacterEncoding設(shè)置的是encoding,這個(gè)是在解析POST的參數(shù)是才用到 的。
????所以,這就導(dǎo)致了我們通常都要分開處理POST和GET的字符編碼,用TOMCAT自帶的filter只能處理POST的,另外要設(shè)置URIEncoding來設(shè)置GET的。這樣很麻煩而且URIEncoding無法根據(jù)內(nèi)容來動(dòng)態(tài)區(qū)分編碼,總還是一個(gè)問題。
????在調(diào)查TOMCAT的代碼時(shí)發(fā)現(xiàn)了另一個(gè)在server.xml里的參數(shù)useBodyEncodingForURI,可以解決這個(gè)問題。這個(gè)參數(shù)設(shè)成 true后,TOMCAT就會(huì)用request.setCharacterEncoding所設(shè)置的字符編碼來同樣解析GET參數(shù)了。這樣,那個(gè) SetCharacterEncodingFilter就可以同時(shí)處理GET和POST參數(shù)了。
????知道了以上知識(shí)后,我們?cè)賮矸治鲆幌虑懊姹砀裰辛谐龅膸讉€(gè)典型現(xiàn)象。
????第一條,請(qǐng)求源頁面的編碼為UTF-8,而TOMCAT的URIEncoding未指定,則TOMCAT用ISO8859-1方式來解碼參數(shù),所以從request中讀出來后,內(nèi)存中存儲(chǔ)的為錯(cuò)誤的UNICODE數(shù)據(jù),導(dǎo)致之后到屏幕顯示的所有轉(zhuǎn)換全部出錯(cuò)。
????第九條,請(qǐng)求源頁面編碼為GBK,而TOMCAT的URIEncoding也為GBK,TOMCAT用GBK方式去解碼原本用GBK編碼的字符,解碼正確,內(nèi)存中的UNICODE值正確,最終顯示正確的中文。
????第十三條,請(qǐng)求源頁面編碼為UTF-8,TOMCAT的URIEncoding也為UTF-8,而在IE6中最終顯示的中文字符,如果是奇數(shù)個(gè)數(shù),則最后一個(gè)會(huì)顯示為亂碼。這是為什么呢?
????我的猜測(cè)是,這是因?yàn)镮E6將URL地址發(fā)送時(shí),對(duì)查詢字符串是直接對(duì)UTF-8格式的字符使用GBK來編碼,而不是對(duì)UNICODE的字符來用GBK編 碼,所以UTF-8的數(shù)據(jù)沒有經(jīng)過UNICODE而直接編碼成了GBK。而到了TOMCAT這邊,GBK的編碼又被當(dāng)成UTF-8做了解碼。所以這個(gè)過程 中經(jīng)過了UTF-8轉(zhuǎn)換成GBK,然后又從GBK轉(zhuǎn)換成UTF-8的過程,而這種轉(zhuǎn)換,恰好就會(huì)出現(xiàn)奇數(shù)個(gè)中文字符串的最后一位為亂碼的現(xiàn)象。而在IE7 中,估計(jì)把這種現(xiàn)象當(dāng)做BUG已經(jīng)被解決了,即在發(fā)送地址時(shí)會(huì)先轉(zhuǎn)成UNICODE再編碼成GBK。那么估計(jì)在IE7的瀏覽器+中文操作系統(tǒng)環(huán)境下,如果 我們把TOMCAT的URIEncoding設(shè)置成GBK,無論JSP編碼成什么格式,都不會(huì)出現(xiàn)亂碼。這個(gè)沒測(cè)試,請(qǐng)大家自己驗(yàn)證。
????其他幾條就不再做分析了,有興趣的大家自己分析。
?
參考:
http://blog.csdn.net/lfsf802/article/details/7232834
http://blog.sina.com.cn/s/blog_95c8f1ac010198j2.html
轉(zhuǎn)載于:https://my.oschina.net/trydaydayup/blog/1503817
總結(jié)
以上是生活随笔為你收集整理的form表单提交数据编码方式和tomcat接受数据解码方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安天365第二期线上交流
- 下一篇: FragmentTabHost的应用