總結html
1.經過瀏覽器向服務器發送請求,瀏覽器會根據自帶的默認編碼格式自動對URL進行編碼。(注意是URL不包含 request boby部分);java
2.服務器接收請求,會按照tomcat中設置的編碼格式自動對URL進行解碼。因此當瀏覽器與服務器的編碼格式設置不相同,則URL中有中文的部分就會出現亂碼。程序員
post請求中,request body中的內容的編碼格由 request.setCharacterEncoding()決定web
///////////////////////////////////////////////////////////////////////////////////////////////////////////api
瀏覽器URL編碼瀏覽器
轉:http://www.cnblogs.com/haitao-fan/p/3399018.htmltomcat
轉:http://blog.csdn.net/yzhz/article/details/1676796服務器
深刻淺出URL編碼網絡
1、問題:
編碼問題是Java初學者在web開發過程當中常常會遇到問題,網上也有大量相關的文章介紹,但其中不少文章並無對URL中使用了中文等非ASCII的字符形成服務器後臺程序解析出現亂碼的問題做出準確的解釋和說明。本文將詳細介紹因爲在URL中使用了中文等非ASCII的字符形成亂碼的問題。app
一、在URL中中文字符一般出如今如下兩個地方:
(1)、Query String中的參數值,好比http://search.china.alibaba.com/search/offer_search.htm?keywords=中國
(2)、servlet path,好比:http://search.china.alibaba.com/selloffer/中國.html
二、出現亂碼問題的緣由主要是如下幾方面:
(1)、瀏覽器:咱們的客戶端(瀏覽器)自己並無遵循URI編碼的規範(http://www.w3.org/International/O-URL-code.html)。
(2)、Servlet服務器:Servlet服務器的沒有正確配置。
(3)、開發人員並不瞭解Servlet的規範和API的含義。
2、基礎知識:
一、一個http請求通過的幾個環節:
瀏覽器(ie firefox)【get/post】------------>Servlet服務器------------------------------->瀏覽器顯示
編碼 解碼成unicode,而後將顯示的內容編碼 解碼
(1) 瀏覽器把URL(以及post提交的內容)通過編碼後發送給服務器。
(2) 這裏的Servlet服務器實際上指的是由Servlet服務器提供的servlet實現ServletRequestWrapper,不一樣應用服務器的servlet實現不一樣,這些servlet的實現把這些內容解碼轉換爲unicode,處理完畢後,而後再把結果(即網頁)編碼返回給瀏覽器。
(3) 瀏覽器按照指定的編碼顯示該網頁。
當對字符串進行編碼和解碼的時候都涉及到字符集,一般使用的字符集爲ISO8859-一、GBK、UTF-八、UNICODE。
二、URL的組成:
域名:端口/contextPath/servletPath/pathInfo?queryString
說明:
一、ContextPath是在Servlet服務器的配置文件中指定的。
對於weblogic:
contextPath是在應用的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是在應用的jboss-web.xml中配置。
<jboss-web>
<context-root>/</context-root>
</jboss-web>
二、ServletPath是在應用的web.xml中配置。
<servlet-mapping>
<servlet-name>Example</servlet-name>
<url-pattern>/example/*</url-pattern>
</servlet-mapping>
二、Servlet API
咱們使用如下servlet API得到URL的值及參數。
request.getParameter("name"); // 得到queryString的參數值(來自於get和post),其值通過Servlet服務器URL Decode過的
request.getPathInfo(); // 注意:pathinfo返回的字符串是通過Servlet服務器URL Decode過的。
requestURI = request.getRequestURI(); // 內容爲:contextPath/servletPath/pathinfo 瀏覽器提交過來的原始數據,未被Servlet服務器URL Decode過。
三、開發人員必須清楚的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、下面咱們分別從瀏覽器和應用服務器來舉例說明:
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]信息失去
(一)、瀏覽器
一、GET方式提交,瀏覽器會對URL進行URL encode,而後發送給服務器。
(1) 對於中文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
(1) 對於中文IE,若是在高級選項中取消總以UTF-8發送,則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
很顯然,不一樣的瀏覽器以及同一瀏覽器的不一樣設置,會影響最終URL中PathInfo的編碼。對於中文的IE和FIREFOX都是採用GBK編碼QueryString。
小結:解決方案:
一、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
二、咱們建議URL中PathInfo和QueryString採用相同的編碼,這樣對服務器端處理的時候會更加簡單。
二、還有一個問題,我發現不少程序員並不明白URL Encode是須要指定字符集的。不明白的人能夠看看這篇文檔:http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/net/URLEncoder.html
二、 POST提交
對於POST方式,表單中的參數值對是經過request body發送給服務器,此時瀏覽器會根據網頁的ContentType("text/html; charset=GBK")中指定的編碼進行對錶單中的數據進行編碼,而後發給服務器。
在服務器端的程序中咱們能夠經過Request.setCharacterEncoding() 設置編碼,而後經過request.getParameter得到正確的數據。
解決方案:
一、從最簡單,所需代價最小來看,咱們對URL以及網頁中的編碼使用統一的編碼對咱們來講是比較合適的。
若是不使用統一編碼的話,咱們就須要在程序中作一些編碼轉換的事情。這也是咱們爲何看到有網絡上大量的資料介紹如何對亂碼進行處理,其中不少解決方案都只是一時的權宜之計,沒有從根本上解決問題。
(二)、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"/>
URIEncoding告訴服務器servlet解碼URL時採用的編碼。
<Connector port="8080" ... useBodyEncodingForURI="true" />
useBodyEncodingForURI告訴服務器解碼URL時候須要採用request body指定的編碼。
(2) weblogic服務器
對於weblogic服務器,該文件是weblogic.xml
<input-charset>
<java-charset-name>GBK</java-charset-name>
</input-charset>
(三)瀏覽器顯示
瀏覽器根據http頭中的ContentType("text/html; charset=GBK"),指定的字符集來解碼服務器發送過來的字節流。咱們能夠調用HttpServletResponse.setContentType()設置http頭的ContentType。
總結:
一、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一般會採用相同的字符集來解碼。
二、咱們建議URL中的URL Encode編碼的字符集和網頁的contentType的字符集採用相同的字符集,這樣程序的實現就很簡單,不用作複雜的編碼轉換。