<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    jsp編碼問題

    Posted on 2010-06-01 17:31 瘋狂 閱讀(3142) 評論(0)  編輯  收藏 所屬分類: web

    轉(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-1、GBK、UTF-8、UNICODE。


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

    1、ContextPath是在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>

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

    2、Servlet API
    我們使用以下servlet API獲得URL的值及參數(shù)。
    request.getParameter("name");         // 獲得queryString的參數(shù)值(來自于get和post),其值經(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ù)器來舉例說明:
    URL:http://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ā)送(默認方式),則PathInfo是URL 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ā)送,則PathInfo和QueryString是URL encode按照GBK編碼。
    實際上提交是:
    GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

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

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

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

    2、我們建議URL中PathInfo和QueryString采用相同的編碼,這樣對服務(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遇到URL和POST提交的數(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中的PathInfo和QueryString字符串的編碼和解碼是由瀏覽器和應(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中不要在PathInfo和QueryString同時使用非ASCII字符,比如
    http://localhost:8080/example1/example/中國?name=中國
    原因很簡單:不同瀏覽器對URL中PathInfo和QueryString編碼時采用的字符集不同,但應(yīng)用服務(wù)器對URL通常會采用相同的字符集來解碼。

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

    -----自己的一些總結(jié):

    jsp編碼相關(guān)-----------------------------
    1. pageEncoding: 只是指明了 JSP 頁面本身的編碼格式,跟頁面顯示的編碼沒有關(guān)系;
        容器在讀取(文件)或者(數(shù)據(jù)庫)或者(字符串常量)時將起轉(zhuǎn)化為內(nèi)部使用的 Unicode,而頁面顯示的時候?qū)?br />     內(nèi)部的Unicode轉(zhuǎn)換為contentType指定的編碼后顯示頁面內(nèi)容;
        如果pageEncoding屬性存在,那么JSP頁面的字符編碼方式就由pageEncoding決定,
        否則就由contentType屬性中的charset決定,如果charset也不存在,JSP頁面的字符編碼方式就采用
        默認的ISO-8859-1。
        2. contentType: 指定了MIME類型和JSP頁面回應(yīng)時的字符編碼方式。MIME類型的默認值是“text/html”;
        字符編碼方式的默認值是“ISO-8859-1”. MIME類型和字符編碼方式由分號隔開;
        3. pageEncoding和contentType的關(guān)系:
            1. pageEncoding的內(nèi)容只是用于jsp輸出時的編碼,不會作為header發(fā)出去的; 是告訴web Server
                jsp頁面按照什么編碼輸出,即web服務(wù)器輸出的響應(yīng)流的編碼;
           2. 第一階段是jsp編譯成.java,它會根據(jù)pageEncoding的設(shè)定讀取jsp,結(jié)果是由指定的編碼方案翻譯
                成統(tǒng)一的UTF-8 JAVA源碼(即.java).
           3. 第二階段是由JAVAC的JAVA源碼至java byteCode的編譯,不論JSP編寫時候用的是什么編碼方案,
                經(jīng)過這個階段的結(jié)果全部是UTF-8的encoding的java源碼.JAVAC用UTF-8的encoding讀取
                java源碼,編譯成UTF-8 encoding的二進制碼(即.class),這是JVM對常數(shù)字串在二進制碼
                (java encoding)內(nèi)表達的規(guī)范.
           4. 第三階段是Tomcat(或其的application container)載入和執(zhí)行階段二的來的JAVA二進制碼,
                輸出的結(jié)果,也就是在客戶端見到的,這時隱藏在階段一和階段二的參數(shù)contentType就發(fā)揮了功效   
        4. 和contentType效果一樣的設(shè)置方式還有 html頁面charset, response.setCharacterEncoding(),
            response.setContentType(),response.setHeader(); response.setContentType(),
            response.setHeader();優(yōu)先級最好,其次是response.setCharacterEncoding();再者是
            <%@page contentType="text/html; chareset=gbk"%>,最后是<meta http-equiv="content-type"
            content="text/html; charset=gb2312" />.
        5. web頁面輸入編碼: 在設(shè)置頁面編碼<%@page contentType="text/html; chareset=gbk"%>的同時,也就指定了頁面的輸入編碼;
            如果頁面的顯示被設(shè)置為UTF-8,那么用戶所有的頁面輸入都會按照 UTF-8 編碼; 服務(wù)器端程序在讀
            取表單輸入之前要設(shè)定輸入編碼;
            表單被提交后,瀏覽器會將表單字段值轉(zhuǎn)換為指定字符集對應(yīng)的字節(jié)值,然后根據(jù) HTTP 標準 URL
            編碼方案對結(jié)果字節(jié)進行編碼.但是頁面需要告訴服務(wù)器當前頁面的編碼方式;
            request.setCharacterEncoding(),能修改Serverlet獲取請求的編碼,response.setCharacterEncoding(),
            能修改Serverlet返回結(jié)果的編碼.
        6;對于get方法表單通過設(shè)置 response.setCharacterEncoding(), 和request.setCharacterEncoding("utf-8")無效,
     get有長度限制,最長不超過2048字節(jié)(1024個漢字)
          

    注意編碼要在獲取寫通道之前設(shè)置:
    response.setContentType("text/html;charset=gbk");
    PrintWriter out = response.getWriter();
    如果寫成如下將導致編碼設(shè)置無效:
    PrintWriter out = response.getWriter();
    response.setContentType("text/html;charset=gbk");
    在設(shè)置編碼之前獲取度通道將導致后期設(shè)置編碼無效
    System.out.println("997:"+request.getParameter("ta"));
    request.setCharacterEncoding("utf-8");
    System.out.println("999:"+request.getParameter("ta"));
    正確如下:
    request.setCharacterEncoding("utf-8");
    System.out.println("999:"+request.getParameter("ta"));
    -----------------------------2--


    主站蜘蛛池模板: 亚洲国产美女视频| 亚洲av无码片在线播放| 亚洲熟女综合色一区二区三区| 99热在线观看免费| 亚洲成A人片在线观看WWW| 中文字幕免费播放| 亚洲人成精品久久久久| 免费无码又爽又刺激一高潮| 亚洲中文字幕无码不卡电影| 国产线视频精品免费观看视频| 亚洲五月综合缴情在线观看| 久久九九全国免费| 99久久精品国产亚洲| 国产福利视精品永久免费| 亚洲国产精品成人综合色在线婷婷| 国产一卡二卡四卡免费| 亚洲国产最大av| 国产又粗又猛又爽又黄的免费视频 | 亚洲成a人无码亚洲成www牛牛| 夜夜嘿视频免费看| 美女羞羞免费视频网站| 亚洲视频在线精品| 四虎国产成人永久精品免费| 亚洲精品国产日韩| 又大又黄又粗又爽的免费视频 | 51在线视频免费观看视频| 亚洲一区二区三区免费在线观看| 成人免费毛片观看| 日韩电影免费在线观看网址| 亚洲中文字幕久久精品无码APP | 亚洲欧美日韩一区二区三区| 亚洲成a人无码av波多野按摩| 两性色午夜视频免费网| 亚洲婷婷天堂在线综合| 国产99视频免费精品是看6| 91精品成人免费国产| 亚洲国产模特在线播放| 国产伦精品一区二区三区免费迷 | 亚洲精品成人片在线播放| 91久久成人免费| xxxxx做受大片视频免费|