• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            深入淺出URL編碼

            版權(quán)聲明:如有轉(zhuǎn)載請求,請注明出處:http://blog.csdn.net/yzhz  楊爭  

            一、問題:
                   
            編碼問題是JAVA初學者在web開發(fā)過程中經(jīng)常會遇到問題,網(wǎng)上也有大量相關(guān)的文章介紹,但其中很多文章并沒有對URL中使用了中文等非ASCII的字符造成服務(wù)器后臺程序解析出現(xiàn)亂碼的問題作出準確的解釋和說明。本文將詳細介紹由于在URL中使用了中文等非ASCII的字符造成亂碼的問題。

            1、在URL中中文字符通常出現(xiàn)在以下兩個地方:
            (1)
            Query String中的參數(shù)值,比如
            http://search.china.alibaba.com/search/offer_search.htm?keywords=中國
            (2)servlet path,比如http://search.china.alibaba.com/selloffer/中國.html


            2、出現(xiàn)亂碼問題的原因主要是以下幾方面:
            (1)
            、瀏覽器:我們的客戶端(瀏覽器)本身并沒有遵循URI編碼的規(guī)范
            http://www.w3.org/International/O-URL-code.html)。
            (
            2)Servlet服務(wù)器:Servlet服務(wù)器的沒有正確配置。
            (3)
            、開發(fā)人員并不了解Servlet的規(guī)范和API的含義。

            二、基礎(chǔ)知識:
            1
            、一個http請求經(jīng)過的幾個環(huán)節(jié):
            瀏覽器(ie firefox)get/post------------>Servlet服務(wù)器------------------------------->瀏覽器顯示
                                          
            編碼                 解碼成unicode,然后將顯示的內(nèi)容編碼        解碼
            (1)
            瀏覽器把URL(以及post提交的內(nèi)容)經(jīng)過編碼后發(fā)送給服務(wù)器。
            (2)
            這里的Servlet服務(wù)器實際上指的是由Servlet服務(wù)器提供的servlet實現(xiàn)ServletRequestWrapper,不同應(yīng)用服務(wù)器的servlet實現(xiàn)不同,這些servlet的實現(xiàn)把這些內(nèi)容解碼轉(zhuǎn)換為unicode,處理完畢后,然后再把結(jié)果(即網(wǎng)頁)編碼返回給瀏覽器。
            (3)
            瀏覽器按照指定的編碼顯示該網(wǎng)頁。

                    當對字符串進行編碼和解碼的時候都涉及到字符集,通常使用的字符集為ISO8859-1GBKUTF-8UNICODE


            2
            URL的組成:
            域名:端口/contextPath/servletPath/pathInfo?queryString
            說明:

            1ContextPath是在Servlet服務(wù)器的配置文件中指定的。
            對于weblogic
            contextPath
            是在應(yīng)用的weblogic.xml中配置。
            <context-root>/</context-root>
             
            對于tomcat
            contextPath
            是在server.xml中配置。
            <Context path="/" docBase="D:/server/blog.war" debug="5" reloadable="true" crossContext="true"/>

            對于jboos
            contextPath
            是在應(yīng)用的jboss-web.xml中配置。
            <jboss-web>
                <context-root>/</context-root>
            </jboss-web>

            2ServletPath是在應(yīng)用的web.xml中配置。
            <servlet-mapping>
                <servlet-name>Example</servlet-name>
                <url-pattern>/example/*</url-pattern>
            </servlet-mapping>

            2Servlet API
            我們使用以下servlet API獲得URL的值及參數(shù)。
            request.getParameter("name");         //
            獲得queryString的參數(shù)值(來自于getpost),其值經(jīng)過Servlet服務(wù)器URL Decode過的
            request.getPathInfo();                //
            注意:pathinfo返回的字符串是經(jīng)過Servlet服務(wù)器URL Decode過的。
            requestURI = request.getRequestURI(); //
            內(nèi)容為:contextPath/servletPath/pathinfo 瀏覽器提交過來的原始數(shù)據(jù),未被Servlet服務(wù)器URL Decode過。


            3
            、開發(fā)人員必須清楚的servlet規(guī)范:
            (1) HttpServletRequest.setCharacterEncoding()
            方法 僅僅只適用于設(shè)置post提交的request body的編碼而不是設(shè)置get方法提交的queryString的編碼。該方法告訴應(yīng)用服務(wù)器應(yīng)該采用什么編碼解析post傳過來的內(nèi)容。很多文章并沒有說明這一點。
            (2) HttpServletRequest.getPathInfo()
            返回的結(jié)果是由Servlet服務(wù)器解碼(decode)過的。
            (3) HttpServletRequest.getRequestURI()
            返回的字符串沒有被Servlet服務(wù)器decoded過。
            (4) POST
            提交的數(shù)據(jù)是作為request body的一部分。
            (5)
            網(wǎng)頁的Http頭中ContentType("text/html; charset=GBK")的作用:
               (a)
            告訴瀏覽器網(wǎng)頁中數(shù)據(jù)是什么編碼;
               (b)
            表單提交時,通常瀏覽器會根據(jù)ContentType指定的charset對表單中的數(shù)據(jù)編碼,然后發(fā)送給服務(wù)器的。
              
            這里需要注意的是:這里所說的ContentType是指http頭的ContentType,而不是在網(wǎng)頁中meta中的ContentType


            三、下面我們分別從瀏覽器和應(yīng)用服務(wù)器來舉例說明:
            URLhttp://localhost:8080/example/中國?name=中國
            漢字   編碼      二進制表示
            中國   UTF-8     0xe4 0xb8 0xad 0xe5 0x9b 0xbd[-28, -72, -83, -27, -101, -67]
            中國   GBK       0xd6 0xd0 0xb9 0xfa[-42, -48, -71, -6]
            中國   ISO8859-1 0x3f,0x3f[63, 63]信息失去


            (
            )、瀏覽器
            1
            GET方式提交,瀏覽器會對URL進行URL encode,然后發(fā)送給服務(wù)器。
            (1)
            對于中文IE,如果在高級選項中選中總以UTF-8發(fā)送(默認方式),則PathInfoURL Encode是按照UTF-8編碼,QueryString是按照GBK編碼。
            http://localhost:8080/example/中國?name=中國
            實際上提交是:
            GET /example/%E4%B8%AD%E5%9B%BD?name=%D6%D0%B9%FA

            (1) 對于中文IE,如果在高級選項中取消總以UTF-8發(fā)送,則PathInfoQueryStringURL encode按照GBK編碼。
            實際上提交是:
            GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

            (3) 對于中文firefox,則pathInfoqueryString都是URL encode按照GBK編碼。
            實際上提交是:
            GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

            很顯然,不同的瀏覽器以及同一瀏覽器的不同設(shè)置,會影響最終URLPathInfo的編碼。對于中文的IEFIREFOX都是采用GBK編碼QueryString

            小結(jié):解決方案:
            1
            URL中如果含有中文等非ASCII字符,則瀏覽器會對它們進行URLEncode。為了避免瀏覽器采用了我們不希望的編碼,所以最好不要在URL中直接使用非ASCII字符,而采用URL Encode編碼過的字符串%.
            比如:
            URLhttp://localhost:8080/example/中國?name=中國
            建議:
            URL
            http://localhost:8080/example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

            2、我們建議URLPathInfoQueryString采用相同的編碼,這樣對服務(wù)器端處理的時候會更加簡單。

            2、還有一個問題,我發(fā)現(xiàn)很多程序員并不明白URL Encode是需要指定字符集的。不明白的人可以看看這篇文檔:http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/net/URLEncoder.html

            2 POST提交
                   
            對于POST方式,表單中的參數(shù)值對是通過request body發(fā)送給服務(wù)器,此時瀏覽器會根據(jù)網(wǎng)頁的ContentType("text/html; charset=GBK")中指定的編碼進行對表單中的數(shù)據(jù)進行編碼,然后發(fā)給服務(wù)器。
            在服務(wù)器端的程序中我們可以通過Request.setCharacterEncoding() 設(shè)置編碼,然后通過request.getParameter獲得正確的數(shù)據(jù)。

            解決方案:
            1
            、從最簡單,所需代價最小來看,我們對URL以及網(wǎng)頁中的編碼使用統(tǒng)一的編碼對我們來說是比較合適的。
            如果不使用統(tǒng)一編碼的話,我們就需要在程序中做一些編碼轉(zhuǎn)換的事情。這也是我們?yōu)槭裁纯吹接芯W(wǎng)絡(luò)上大量的資料介紹如何對亂碼進行處理,其中很多解決方案都只是一時的權(quán)宜之計,沒有從根本上解決問題。


            (
            )Servlet服務(wù)器
                    Servlet
            服務(wù)器實現(xiàn)的Servlet遇到URLPOST提交的數(shù)據(jù)中含有%的字符串,它會按照指定的字符集解碼。下面兩個Servlet方法返回的結(jié)果都是經(jīng)過解碼的:
            request.getParameter("name");
            request.getPathInfo();

            這里所說的"指定的字符集"是在應(yīng)用服務(wù)器的配置文件中配置。

            (1) tomcat服務(wù)器
            對于tomcat服務(wù)器,該文件是server.xml
            <Connector port="8080" protocol="HTTP/1.1"
                           maxThreads="150" connectionTimeout="20000"
                           redirectPort="8443" URIEncoding="GBK"/>
            URIEncoding
            告訴服務(wù)器servlet解碼URL時采用的編碼。

            <Connector port="8080" ... useBodyEncodingForURI="true" />
            useBodyEncodingForURI
            告訴服務(wù)器解碼URL時候需要采用request body指定的編碼。

            (2) weblogic服務(wù)器
            對于weblogic服務(wù)器,該文件是weblogic.xml
            <input-charset>
              <java-charset-name>GBK</java-charset-name>
            </input-charset>

            ()瀏覽器顯示
                   
            瀏覽器根據(jù)http頭中的ContentType("text/html; charset=GBK"),指定的字符集來解碼服務(wù)器發(fā)送過來的字節(jié)流。我們可以調(diào)用HttpServletResponse.setContentType()設(shè)置http頭的ContentType

            總結(jié):
            1
            URL中的PathInfoQueryString字符串的編碼和解碼是由瀏覽器和應(yīng)用服務(wù)器的配置決定的,我們的程序不能設(shè)置,不要期望用request.setCharacterEncoding()方法能設(shè)置URL中參數(shù)值解碼時的字符集。
            所以我們建議URL中不要使用中文等非ASCII字符,如果含有非ASCII字符的話要使用URLEncode編碼一下,比如:
            http://localhost:8080/example1/example/中國
            正確的寫法:
            http://localhost:8080/example1/example/%E4%B8%AD%E5%9B%BD
            并且我們建議URL中不要在PathInfoQueryString同時使用非ASCII字符,比如
            http://localhost:8080/example1/example/
            中國?name=中國
            原因很簡單:不同瀏覽器對URLPathInfoQueryString編碼時采用的字符集不同,但應(yīng)用服務(wù)器對URL通常會采用相同的字符集來解碼。

            2、我們建議URL中的URL Encode編碼的字符集和網(wǎng)頁的contentType的字符集采用相同的字符集,這樣程序的實現(xiàn)就很簡單,不用做復雜的編碼轉(zhuǎn)換。

            發(fā)表于 @ 2007年07月03 15:14:00 | 評論( 18 ) | 編輯| 舉報| 收藏

            pwlazy 發(fā)表于200775 15:42:21  IP:舉報

            有個疑問?
            原文1
            (b)
            表單提交時,通常瀏覽器會根據(jù)ContentType指定的charset對表單中的數(shù)據(jù)編碼,然后發(fā)送給服務(wù)器的。
            原文2
            很顯然,不同的瀏覽器以及同一瀏覽器的不同設(shè)置,會影響最終URLPathInfo的編碼。對于中文的IEFIREFOX都是采用GBK編碼QueryString

            那么瀏覽器提交的時候到底按哪個標準編碼?
            難道原文1處指的是post?原文2處指的是get?

            yzhzclip_image001 發(fā)表于200775 15:50:47  IP:舉報

            是的,原文1是指post的方式,因為get方式的時候用戶只輸入url,瀏覽器沒有什么編碼可參考,所以get方式的時候瀏覽器采用自己的規(guī)定去編碼url

            對于post方式,由于服務(wù)器先前已返回了網(wǎng)頁給瀏覽器,所以post的時候瀏覽器會根據(jù)網(wǎng)頁的contenttype來編碼表單的數(shù)據(jù)。

            pwlazy 發(fā)表于200775 15:56:33  IP:舉報

            如果提交的數(shù)據(jù)中不含%,服務(wù)器又該如何解碼

            yzhzclip_image001 發(fā)表于200775 16:31:40  IP:舉報

            呵呵,你可以看看java.net.URLDecoderdecode方法是怎么做的?它按照字符集,該怎么做就怎么做。
            package java.net;
            public class URLDecoder {
            public static String decode(String s, String enc)
            throws UnsupportedEncodingException{

            boolean needToChange = false;
            int numChars = s.length();
            StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
            int i = 0;

            if (enc.length() == 0) {
            throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
            }

            char c;
            byte[] bytes = null;
            while (i < numChars) {
            c = s.charAt(i);
            switch (c) {
            case '+':
            sb.append(' ');
            i++;
            needToChange = true;
            break;
            case '%':
            /*
            * Starting with this instance of %, process all
            * consecutive substrings of the form %xy. Each
            * substring %xy will yield a byte. Convert all
            * consecutive bytes obtained this way to whatever
            * character(s) they represent in the provided
            * encoding.
            */

            try {

            // (numChars-i)/3 is an upper bound for the number
            // of remaining bytes
            if (bytes == null)
            bytes = new byte[(numChars-i)/3];
            int pos = 0;

            while ( ((i+2) < numChars) &&
            (c=='%')) {
            bytes[pos++] =
            (byte)Integer.parseInt(s.substring(i+1,i+3),16);<

            pwlazy 發(fā)表于200775 17:17:54  IP:舉報

            你給我的這段代碼實際上已經(jīng)假定傳入了編碼即enc,否則會拋意外
            我想問的其實是如果不通過瀏覽器請求,通過應(yīng)用程序或者腳本請求某個url,而且這個url并未顯式的編碼,那最終發(fā)送的服務(wù)器的url的編碼情況是怎樣的

            yzhzclip_image001 發(fā)表于200775 17:28:39  IP:舉報

            那服務(wù)器會通過默認的編碼解析URL

            當存在這種情況的話,我們通常的做法是雙方約定好url采用的編碼,這樣服務(wù)器端的servlet根據(jù)約定好的編碼去解析url

            pwlazy 發(fā)表于200775 17:38:25  IP:舉報

            比如我在程序中發(fā)送請求http://xxx.com?y=中國,到服務(wù)器的時候
            "
            中國"兩個字編碼情況是怎樣(此時服務(wù)器還沒開始解碼)

            yzhzclip_image001 發(fā)表于200775 17:56:26  IP:舉報

            舉個例子:
            如果你采用httpClient來發(fā)送這個url的話,httpclient會把這個url encode,然后發(fā)送給服務(wù)器。這時候encode采用的字符集為httpclient默認的字符集。

            所以我建議如果你的url帶有中文等非ascii字符的話,你最好自己先encode,這樣httpclient encode的時候就不會對這些字符進行改變,這樣你就控制url的編碼,比如我采用gbk,那么我發(fā)送的url就是:

            String url = http://xxx.com?y=%D6%D0%B9%FA
            HttpClient client = new HttpClient();
            GetMethod method = new GetMethod(url);

            yzhzclip_image001 發(fā)表于200775 17:58:58  IP:舉報

            接上面:
            那么服務(wù)器端按照gbk解碼就可以了。
            所以一句話,采用get方式最重要的是發(fā)送方和接收方都約定好編碼。

            pwlazy 發(fā)表于200776 10:56:19  IP:舉報

            謝謝你的回答
            另外一個問題:
            我一個應(yīng)用全部使用utf-8 編碼,頁面metaurlencode,數(shù)據(jù)庫,服務(wù)器tomcat使用默認編碼iso- 8859-1

            使用post提交中文的時候,無須轉(zhuǎn)碼OK
            但采用get+urlencode的時候必須后臺轉(zhuǎn)碼iso-8859-1---utf-8

            這個原因是什么?按照你上面說的,我頁面的metautf-8,那么form提交應(yīng)該是utf-8編碼,那么應(yīng)該和get+urlencode效果一樣,但到服務(wù)器端的時候,前者需要轉(zhuǎn)碼后者不需要,難道服務(wù)器只對get解碼而不理會post

            yzhzclip_image001 發(fā)表于200776 11:13:31  IP:舉報

            沒看明白,你現(xiàn)在是get方式提交是好的,還是post方式提交是好的。

            有幾個問題,你要告訴我。
            1
            、在tomcat的配置中URIEncodinguseBodyEncodingForURI的值是多少,你的tomcat版本是多少?
            <Connector port="8080" protocol="HTTP/1.1"
            maxThreads="150" connectionTimeout="20000"
            redirectPort="8443" URIEncoding="GBK" useBodyEncodingForURI="true"/>
            2
            、頁面meta寫明是編碼有時候是沒有用的,關(guān)鍵是你的http頭中的編碼是什么,就是HttpServletResponse.setContentType()設(shè)置http頭的ContentType的編碼是什么?

            pwlazy 發(fā)表于200776 11:28:24  IP:舉報

            我現(xiàn)在post提交沒問題
            get+urlencode
            也沒問題,但是需要在后臺轉(zhuǎn)一下碼(iso-8859-1---utf-8

            我沒弄明白為什么后者需要轉(zhuǎn)碼,前者不需要
            你有msn嗎? 我的pwlazy@sina.com

            yzhzclip_image001 發(fā)表于200776 15:50:22  IP:舉報

            yangzheng027@hotmail.com

            xyf197879 發(fā)表于20071113 16:58:21  IP:舉報

            如果我在IE7中直接輸入"http://localhost:8080/example1/example/中國?name=中國",是怎樣處理的?

            mlz_2 發(fā)表于200857 12:36:27  IP:舉報

            謝謝,
            我遇到了類似的問題,當post的時候,中文不會亂碼;而使用GET的時候,中文就會亂碼

            我使用的是UTF-8的編碼,使用get方式,在接收端發(fā)現(xiàn)中文被轉(zhuǎn)換成gb2312

            讀完此文,大概知道了原因,也就不在嘗試其他解決辦法了,而是直接使用post方式,就不會轉(zhuǎn)碼了。

            sfdev 發(fā)表于2009120 20:43:04  IP:舉報

            好文,不過文檔里面有些測試結(jié)果應(yīng)該是有前置條件的,比如queryString為什么用GBK編碼、可能會用其他字符集來編碼嗎?
            我在本文的基礎(chǔ)上我進一步整理了下,具體見《中文化和國際化問題權(quán)威解析之五:URL編碼/Misc》;
            http://blog.csdn.net/sfdev/archive/2009/01/20/3841719.aspx

            sfdev 發(fā)表于2009120 20:43:42  IP:舉報

            好文,不過文檔里面有些測試結(jié)果應(yīng)該是有前置條件的,比如queryString為什么用GBK編碼、可能會用其他字符集來編碼嗎?
            我在本文的基礎(chǔ)上我進一步整理了下,具體見《中文化和國際化問題權(quán)威解析之五:URL編碼/Misc》;
            http://blog.csdn.net/sfdev/archive/2009/01/20/3841719.aspx

            swit1983 發(fā)表于200986 14:35:58  IP:舉報

            我在jspcharset=gbk)里面用ajax 的時候querystring中用js的函數(shù)URIencode() 服務(wù)器用URIdecode可以,但是用window.location.href=...../?area=德清用上面同樣的方法怎么不行啊?

             

            posted on 2009-09-08 18:33 肥仔 閱讀(4923) 評論(0)  編輯 收藏 引用 所屬分類: HTTP & URL

            久久99精品国产一区二区三区| 人人狠狠综合久久亚洲88| 久久久久亚洲AV成人网| 日韩一区二区三区视频久久| 日本WV一本一道久久香蕉| 97久久精品人妻人人搡人人玩| 色综合久久天天综合| 精品国产日韩久久亚洲| 亚洲国产精品久久久久网站| 亚洲国产香蕉人人爽成AV片久久| 久久精品人人槡人妻人人玩AV | 久久久无码一区二区三区| 国内精品久久久久久野外| 久久青青色综合| 久久成人国产精品二三区| 久久久久精品国产亚洲AV无码| 久久99国产精品久久久| 久久国内免费视频| 久久99精品九九九久久婷婷| 蜜臀av性久久久久蜜臀aⅴ麻豆 | 国内精品久久久久久久久电影网 | 久久天天躁狠狠躁夜夜躁2O2O| 国产精品热久久毛片| av午夜福利一片免费看久久| 久久精品成人免费观看97| 久久久久国产精品人妻| 久久久网中文字幕| 久久久久久久国产免费看| 亚洲国产精品久久久久婷婷软件| 久久精品国产99久久无毒不卡 | 久久久久国产精品三级网| 久久国产精品-国产精品| 亚洲国产精品18久久久久久| 久久强奷乱码老熟女网站| 色综合久久久久综合99| 久久久综合香蕉尹人综合网| 久久久久亚洲av成人无码电影 | 国产精品久久精品| 色综合久久久久网| 精品久久人人做人人爽综合 | 囯产精品久久久久久久久蜜桃 |