1. 程式人生 > >在URL中傳遞中文的解決方式

在URL中傳遞中文的解決方式

在URL中傳遞中文的解決方式

2015年05月13日 17:13:55 thinkinglink 閱讀數:10321 標籤: URL編碼中文編碼亂碼解決 更多

個人分類: web前端

在URL中傳遞中文的解決方式

1.第一種方式,主要是通過配置搞定 
1.1)在伺服器端設定 
(1)在tomcat的配置檔案中指定編碼 
server.xml檔案中指定:URIEncoding=”UTF-8”

<Connector connectionTimeout="20000" port="8080" 
                protocol="HTTP/1.1" redirectPort="8443" 
                useBodyEncodingForURI="true" URIEncoding="UTF-8"/>
  • 1
  • 2
  • 3

URIEncoding告訴伺服器servlet解碼URL時採用的編碼; 
useBodyEncodingForURI 告訴伺服器解碼URL時候需要採用request body指定的編碼

(2)在weblogic伺服器的配置檔案中指定編碼 
weblogic.xml 檔案中指定UTF-8

    <input-charset> 
        <java-charset-name>UTF-8</java-charset-name> 
    </input-charset>    
  • 1
  • 2
  • 3

1.2)在瀏覽器端設定 
在頁面設定檔案的編碼和儲存格式UTF-8 
在頁面頭設定:pageEncoding=”UTF-8” contentType=”text/html; charset=UTF-8” 
在HtmL中的meta設定:

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  • 1

這樣設定後,滿足在主流瀏覽器:chrome、firefox等瀏覽器URL中帶有中文的請求自動轉碼問題, 
不需要額外在後臺程式碼裡進行手動轉碼。 
但是,對獨樹一幟的IE大瀏覽器仍舊不起效果,會出現令人頭疼的亂碼問題。解決方案看第3步了

1.3)在前端用js對URL進行編碼後再發送請求(僅僅只是為了相容IE) 
var srcUrl = _contextEbtPath + “/dic/index?condition=我是中文查詢條件撒”; 
var encodeUrl = encodeURI(srcUrl); 
這樣編碼一次後,也不會影響其他主流瀏覽器的編碼轉換問題,得到徹底解決。

2.第二種也是最直接的方式,用硬編碼解決 
直接在後臺請求處理前,手動進行一次轉碼。 
缺點是凡是有中文請求URL的都需要硬編碼一次,優點是直接明瞭。

condition = new String(condition.getBytes("iso8859-1"),"utf-8"); 
  • 1

3.相關知識延伸閱讀 
3.1)在URL中中文字元通常出現在以下兩個地方: 
http://localhost:8080/example/中 國 name=中國 
(1)Query String中的引數值,比如 keywords=中國 
(2)servlet path,比如: /中 國 
3.2)出現亂碼問題的原因主要是以下幾方面: 
(1)瀏覽器:我們的客戶端(瀏覽器)本身並沒有遵循URI編碼的規範。 
(2)Servlet伺服器:Servlet伺服器的沒有正確配置。 
3.3)相關知識:http請求的幾個環節 
瀏覽器(ie firefox)—————–>Servlet伺服器 ——————–>瀏覽器顯示 
<編碼> < 解碼成unicode,然後將顯示的內容編碼> <解碼> 
(1)瀏覽器把URL(以及post提交的內容)經過編碼後傳送給伺服器。 
(2)這裡的Servlet伺服器實際上指的是由Servlet伺服器提供的servlet實現ServletRequestWrapper, 
不同應用伺服器的 servlet實現不同,這些servlet的實現把這些內容解碼轉換為unicode, 
處理完畢後,然後再把結果(即網頁)編碼返回給瀏覽器。 
(3)瀏覽器按照指定的編碼顯示該網頁。 
注意: 
當對字串進行編碼和解碼的時候都涉及到字符集,通常使用的字符集為ISO8859-1、GBK、UTF-8、UNICODE。 
3.4)相關知識:URL的組成及說明 
域名:埠/contextPath/servletPath/pathInfo queryString 
(1)contextPath是在Servlet伺服器的配置檔案中指定的 
(a)對於weblogic:contextPath是在應用 的weblogic.xml中配置。

<context-root>/</context-root> 
  • 1

(b)對於tomcat:contextPath是在server.xml中配置。

<Context path="/" docBase="D:/server/blog.war" debug="5" reloadable="true" crossContext="true"/>
  • 1

(c)對於jboos: contextPath是在應用的jboss-web.xml中配置

<jboss-web> 
        <context-root>/</context-root> 
</jboss-web>
  • 1
  • 2
  • 3

(2)servletPath是在應用的web.xml中配置

<servlet-mapping> 
    <servlet-name>Example</servlet-name> 
    <url-pattern>/example/*</url-pattern> 
</servlet-mapping> 
  • 1
  • 2
  • 3
  • 4

3.5)相關知識:Servlet獲取URL的值及引數 API 
(1)獲得 queryString的引數值(來自於GET和POST),其值經過Servlet伺服器URL Decode 過的 
request.getParameter(“name”); 
(2)獲取 pathinfo 資訊,返回的字串是經過Servlet伺服器URL Decode過的 
request.getPathInfo(); 
(3)獲取 requestURI 瀏覽器提交過來的原始資料,未被Servlet伺服器URL Decode過。 
requestURI = request.getRequestURI();

3.6)相關知識:servlet規範(開發人員必須清楚的servlet規範:) 
(1) HttpServletRequest.setCharacterEncoding()方法 僅僅只適用於設定post提交的request body的編碼而不是設定get方法提交的queryString的編碼。 
該方法告訴應用伺服器應該採用什麼編碼解析post傳過來的內容。很多文章並沒有說明這一點。 
(2) HttpServletRequest.getPathInfo()返回的結果是由Servlet伺服器解碼(decode)過的。 
(3) HttpServletRequest.getRequestURI()返回的字串沒有被Servlet伺服器decoded過。 
(4) POST提交的資料是作為request body的一部分。 
(5) 網頁的Http頭中ContentType(“text/html; charset=GBK”)的作用: 
(a) 告訴瀏覽器網頁中資料是什麼編碼; 
(b) 表單提交時,通常瀏覽器會根據ContentType指定的charset對錶單中的資料編碼,然後傳送給伺服器的。 
這裡需要注意的是:這裡所說的ContentType是指http頭的ContentType,而不是在網頁中meta中的ContentType。 
3.7)瀏覽器和伺服器對編碼的解析 
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]資訊失去 
3.7.1)瀏覽器傳送請求時的編碼 
<1>GET方式提交,瀏覽器會對URL進行URL encode,然後傳送給伺服器。 
(a)對於中文IE,如果在高階選項中選中總以UTF-8傳送(預設方式),則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 
(b)對於中文IE,如果在高階選項中取消總以UTF-8傳送,則PathInfo和QueryString是URL encode按照GBK編碼。 
實際上提交是:GET /example/%D6%D0%B9%FA name=%D6%D0%B9%FA 
(c)對於中文firefox,則pathInfo和queryString都是URL encode按照GBK編碼。 
實際上提交是:GET /example/%D6%D0%B9%FA name=%D6%D0%B9%FA 
很顯然,不同的瀏覽器以及同一瀏覽器的不同設定,會影響最終URL中PathInfo的編碼。 
對於中文的IE和FIREFOX都是採用GBK編碼 QueryString。 
小結,解決方案: 
(a)**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 
(b)我們建議URL中PathInfo和QueryString採用相同的編碼,這樣對伺服器端處理的時候會更加簡單。 
<2>POST方式提交 
對於POST方式,表單中的引數值對是通過request body傳送給伺服器,**此時瀏覽器會根據網頁的ContentType(“text/html; charset=GBK”) 
中指定的編碼進行對錶單中的資料進行編碼**,然後發給伺服器。 
在伺服器端的程式中我們可以通過 Request.setCharacterEncoding() 設定編碼,然後通過request.getParameter獲得正確的資料。 
解決方案: 
從最簡單,所需代價最小來看,我們對URL以及網頁中的編碼使用統一的編碼對我們來說是比較合適的。 
如果不使用統一編碼的話,我們就需要在程式中做一些編碼轉換的事情。這也是我們為什麼看到有網路上大量的資料介紹如何對亂碼進行處理, 
其中很多解決方案都只是一時的權宜之計,沒有從根本上解決問題。

3.7.2)Servlet伺服器 
Servlet伺服器實現的Servlet遇到URL和POST提交的資料中含有%的字串,它會按照指定的字符集解碼。 
下面兩個Servlet方法返回 的結果都是經過解碼的: 
request.getParameter(“name”); 
request.getPathInfo(); 
這裡所說的”指定的字符集”是在應用伺服器的配置檔案中配置。 
(1) tomcat伺服器 
對於tomcat伺服器,該檔案是server.xml

<Connector port="8080" protocol="HTTP/1.1" 
                maxThreads="150" connectionTimeout="20000" 
                redirectPort="8443" URIEncoding="GBK"/> 
  • 1
  • 2
  • 3

URIEncoding告訴伺服器servlet解碼URL時採用的編碼。

<Connector port="8080" ... useBodyEncodingForURI="true" /> 
  • 1

useBodyEncodingForURI 告訴伺服器解碼URL時候需要採用request body指定的編碼。

(2) weblogic伺服器 
對於weblogic伺服器,該檔案是weblogic.xml

<input-charset> 
    <java-charset-name>GBK</java-charset-name> 
</input-charset> 
  • 1
  • 2
  • 3

3.7.3)瀏覽器顯示 
瀏覽器根據http頭中的ContentType(“text/html; charset=GBK”),指定的字符集來解碼伺服器傳送過來的位元組流。 
我們可以呼叫 HttpServletResponse.setContentType()設定http頭的ContentType。

總結: 
(1)URL中的PathInfo和QueryString字串的編碼和解碼是由瀏覽器和應用伺服器的配置決定的, 
我們的程式不能設定,不要期望用request.setCharacterEncoding()方法能設定URL中引數值解碼時的字符集。 
所以我們建議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編碼時採 用的字符集不同,但應用伺服器對URL通常會 
採用相同的字符集來解碼。

(2)我們建議URL中的URL Encode編碼的字符集和網頁的contentType的字符集採用相同的字符集,這樣程式的實現就很簡單, 
不用做複雜的編碼轉換。 JS中對中文(UTF-8格式儲存的)進行編碼(unicode編碼)的函式常用有:encodeURI(str); encodeURIComponent(str);