1. 程式人生 > >【轉】深入淺出URL編碼

【轉】深入淺出URL編碼

一、問題:
        編碼問題是JAVA初學者在web開發過程中經常會遇到問題,網上也有大量相關的文章介紹,但其中很多文章並沒有對URL中使用了中文等非ASCII的字 符造成伺服器後臺程式解析出現亂碼的問題作出準確的解釋和說明。本文將詳細介紹由於在URL中使用了中文等非ASCII的字元造成亂碼的問題。


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

二、基礎知識:
1、一個http請求經過的幾個環節:
瀏覽器(ie firefox)【get/post】------------>Servlet伺服器------------------------------->瀏覽器顯示
                               編碼                 解碼成unicode,然後將顯示的內容編碼        解碼
(1) 瀏覽器把URL(以及post提交的內容)經過編碼後傳送給伺服器。
(2) 這裡的Servlet伺服器實際上指的是由Servlet伺服器提供的servlet實現ServletRequestWrapper,不同應用伺服器的 servlet實現不同,這些servlet的實現把這些內容解碼轉換為unicode,處理完畢後,然後再把結果(即網頁)編碼返回給瀏覽器。
(3) 瀏覽器按照指定的編碼顯示該網頁。

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


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

1、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>

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

2、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過。


3、開發人員必須清楚的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。


三、下面我們分別從瀏覽器和應用伺服器來舉例說明:
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,然後傳送給伺服器。
(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。

小結:解決方案:
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採用相同的編碼,這樣對伺服器端處理的時候會更加簡單。

2、 POST提交
        對於POST方式,表單中的引數值對是通過request body傳送給伺服器,此時瀏覽器會根據網頁的ContentType("text/html; charset=GBK")中指定的編碼進行對錶單中的資料進行編碼,然後發給伺服器。
在伺服器端的程式中我們可以通過Request.setCharacterEncoding() 設定編碼,然後通過request.getParameter獲得正確的資料。

解決方案:
1、從最簡單,所需代價最小來看,我們對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。

總結:
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的字符集採用相同的字符集,這樣程式的實現就很簡單,不用做複雜的編碼轉換。

相關推薦

深入淺出URL編碼

一、問題:         編碼問題是JAVA初學者在web開發過程中經常會遇到問題,網上也有大量相關的文章介紹,但其中很多文章並沒有對URL中使用了中文等非ASCII的字 符造成伺服器後臺程式解析出現亂碼的問題作出準確的解釋和說明。本文將詳細介紹由於在URL中使用了中文等非ASCII的

H.264編碼原理以及I幀B幀P幀

獨立 像素 疊加 提高 oss 解壓 防止 相同 大小 轉自:http://www.cnblogs.com/herenzhiming/articles/5106178.html 前言 ----------------------- H264是新一代的編碼標準,

python基礎-編碼與解碼

什麽 浪費 2.x sys 拼接 aced tro lte bytes 【轉自:https://www.cnblogs.com/OldJack/p/6658779.html】 一、什麽是編碼 編碼是指信息從一種形式或格式轉換為另一種形式或格式的過程。 在計算機中,編碼,簡而

C/C++.解析URL的轉義字元百分比(%)字串

1、來自:[HTTP]_[C_C++]_[解析URL的轉義字元百分比字串] - 豬一戒 - 部落格園.html(http://www.cnblogs.com/zhuyijie/p/6465303.html) 2、使用環境:我在 使用 libxml2的時候,遇到 檔案編碼不對,它在報錯輸出檔名的時候 如果檔名

深入淺出理解決策樹演算法(二)-ID3演算法與C4.5演算法

從深入淺出理解決策樹演算法(一)-核心思想 - 知乎專欄文章中,我們已經知道了決策樹最基本也是最核心的思想。那就是其實決策樹就是可以看做一個if-then規則的集合。我們從決策樹的根結點到每一個都葉結點構建一條規則。 並且我們將要預測的例項都可以被一條路徑或者一條規則所覆蓋。 如下例:假設我

深入淺出理解決策樹演算法(一)-核心思想

演算法思想 決策樹(decision tree)是一個樹結構(可以是二叉樹或非二叉樹)。 其每個非葉節點表示一個特徵屬性上的測試,每個分支代表這個特徵屬性在某個值域上的輸出,而每個葉節點存放一個類別。 使用決策樹進行決策的過程就是從根節點開始,測試待分類項中相應的特徵屬性,並按照其值選擇

url的三個js編碼函式escape(),encodeURI(),encodeURIComponent()簡介

引子 瀏覽器URl地址,上網一定會用到,但是瀏覽器地址有中文或者瀏覽器url引數操作的時候,經常會用到encodeURIComponent()和decodeURIComponent()以及encodeURI()等等。關於瀏覽器引數操作,請看文章http://www.haor

url的三個js編碼函數escape(),encodeURI(),encodeURIComponent()簡介

encode attribute 翻譯 ans encodeuri meta eric spec 默認 引子 瀏覽器URl地址,上網一定會用到,但是瀏覽器地址有中文或者瀏覽器url參數操作的時候,經常會用到encodeURIComponent()和decodeURICom

瀏覽器中輸入url後發生了什麽

正常 工作 orb 問題: serve es2017 背景 ace perm 原文地址:http://www.jianshu.com/p/c1dfc6caa520 在學習前端的過程中經常看到這樣一個問題:當你在瀏覽器中輸入url後發生了什麽?下面是個人學習過程中的總結,供個

ASP.NET的路由系統:URL與物理文件的分離

url重寫 -s abi 解析 per data屬性 public oge his 表現為請求地址與目標Controller和Action的動態映射的URL路由系統並不是專屬於ASP.NET MVC,而是直接建立在ASP.NET 中。ASP.NET通過URL路由系統實現了請

漢字編碼

國家 標準 thread targe mod 區號 abcd all http 區位碼是國家標準信息交換用漢字編碼GB2312-80中漢字的區位編碼。根據其位置分為94區,每個區94個字符,區的編碼是從1~94,位的編碼從1~64。區位碼的第1個字節是區碼,第2字節是位碼。

依賴註入的威力,.NET Core的魅力:解決MVC視圖中的中文被html編碼的問題

lan .config don nsa nco tor options ring 解決 有園友在博問中提了這樣一個問題 —— .NET Core 中文等非英文文字html編碼輸出問題,到我們的 ASP.NET Core 項目中一看,也是同樣的問題。 比如下面的Razor視圖

11條最全面的C/C++編碼規範總結

(轉自:https://blog.csdn.net/zang141588761/article/details/50608736) 對於不同的程式語言來說,具體的編碼規範可以有很大的不同,但是其宗旨都是一致的,就是保證程式碼在高質量完成需求的同時具備良好的可讀性、可維護性。例如我們可以

PHP獲取重定向URL的幾種方法

有時候我們會在開發中,經常會遇到有URL 301或 302重定向的情況,這時候我們可能需要獲取重定向之後的url,下面我們介紹一下幾種獲取重定向url的方法: 1、用get_headers函式php自帶的get_headers函式可以獲取伺服器響應一個HTTP請求所傳送的所有標頭,我們可以嘗試用該函式實現。

MVC中Controller獲取當前View的URL

ASP.NET通用:  【1】獲取完整url (協議名+域名+虛擬目錄名+檔名+引數)  string url=Request.Url.ToString(); 【2】獲取 虛擬目錄名+頁面名+引數:  string url=Request.RawUrl; (或 

深入淺出mongoose

mongoose是nodeJS提供連線 mongodb的一個庫. 此外還有mongoskin, mongodb(mongodb官方出品). 本人,還是比較青睞mongoose的, 因為他遵循的是一種, 模板式方法, 能夠對你輸入的資料進行自動處理. 有興趣的同學可以去Mong

Node深入淺出 章節總結(第九章 — 玩程序) 完結篇

為了看黑色背景,就轉了過來,眼睛看白色螢幕實在受不鳥! 本章總結將結合個人搭建 egg 引入公司的一些實踐來進行總結,希望能讓大家瞭解到程序管理和叢集分發的重要性。 閱讀完本章你應該理解以下幾點: 為什麼要使用多程序架構啟動服務; 經典的 Master-Worker

為什麼本地開發時使用CURL請求本地URL會卡死

轉自:http://blog.51cto.com/aarons/1583871 2014-11-28 10:46:29 ^_^是在WIN下開發。配置是nignxphp mysql 預設時啟動phpcgi是 D:\php \php-cgi.exe-b 127.0.0.1:9000 -c

正確處理瀏覽器在下載文件時HTTP頭的編碼問題(Content-Disposition)

彈出 強調 header tex 不一定 瀏覽器支持 接下來 解決方案 兼容 最近在做項目時遇到了一個 case :需要實現一個強制在瀏覽器中的下載功能(即強制讓瀏覽器彈出下載對話框),並且文件名必須保持和用戶之前上傳時相同(可能包含非 ASCII 字符)。 前一個需求很容

正確處理瀏覽器在下載檔案時HTTP頭的編碼問題(Content-Disposition)

最近在做專案時遇到了一個 case :需要實現一個強制在瀏覽器中的下載功能(即強制讓瀏覽器彈出下載對話方塊),並且檔名必須保持和使用者之前上傳時相同(可能包含非 ASCII 字元)。 前一個需求很容易實現:使用 HTTP Header 的 Content-Disposition: attachment 即可,