1、爲何要編碼轉義web
一般若是同樣東西須要編碼,說明這樣東西並不適合傳輸。緣由多種多樣,如Size過大,包含隱私數據,對於Url來講,之因此要進行編碼,是由於Url中有些字符會引發歧義。apache
例如Url參數字符串中使用key=value鍵值對這樣的形式來傳參,鍵值對之間以&符號分隔,如/s?q=abc&ie=utf-8。若是你的value字符串中包含了=或者&,那麼勢必會形成接收Url的服務器解析錯誤,所以必須將引發歧義的&和=符號進行轉義,也就是對其進行編碼。json
又如,Url的編碼格式採用的是ASCII碼,而不是Unicode,這也就是說你不能在Url中包含任何非ASCII字符,例如中文。不然若是客戶端瀏覽器和服務端瀏覽器支持的字符集不一樣的狀況下,中文可能會形成問題。瀏覽器
Url編碼的原則就是使用安全的字符(沒有特殊用途或者特殊意義的可打印字符)去表示那些不安全的字符。tomcat
2、哪些字符須要編碼安全
一、URL特殊字符轉義,URL中一些字符的特殊含義,基本編碼規則以下:服務器
一、空格換成加號(+)
二、正斜槓(/)分隔目錄和子目錄
三、問號(?)分隔URL和查詢
四、百分號(%)制定特殊字符
五、#號指定書籤
六、&號分隔參數函數
二、不須要編碼的字符:google
RFC3986文檔對Url的編解碼問題作出了詳細的建議,指出了哪些字符須要被編碼纔不會引發Url語義的轉變,以及對爲何這些字符須要編碼作出了相應的解釋。編碼
一、在US-ASCII字符集中沒有的可打印字符:Url中只容許使用可打印字符。US-ASCII碼中的10-7F字節全都表示控制字符,這些字符都不能直接出如今Url中。同時,對於80-FF字節(ISO-8859-1),因爲已經超出了US-ACII定義的字節範圍,所以也不能夠放在Url中。
二、保留字符:Url能夠劃分紅若干個組件,協議、主機、路徑等。有一些字符(:/?#[]@)是用做分隔不一樣組件的。例如:冒號用於分隔協議和主機,/用於分隔主機和路徑,?用於分隔路徑和查詢參數,等等。還有一些字符(!$&'()*+,;=)用於在每一個組件中起到分隔做用的,如=用於表示查詢參數中的鍵值對,&符號用於分隔查詢多個鍵值對。當組件中的普通數據包含這些特殊字符時,須要對其進行編碼。
RFC3986文檔規定,Url中只容許包含如下四種:
一、英文字母(a-zA-Z)
二、數字(0-9)
三、-_.~ 4個特殊字符
四、全部保留字符,RFC3986中指定了如下字符爲保留字符(英文字符): ! * ' ( ) ; : @ & = + $ , / ? # [ ]
三、須要編碼的字符:
若是須要在URL中用到特殊字符,須要將這些特殊字符換成相應的十六進制的值
不安全字符:有一些字符,當他們直接放在Url中的時候,可能會引發解析程序的歧義。這些字符被視爲不安全字符,緣由有不少。
須要注意的是,對於Url中的合法字符,編碼和不編碼是等價的,可是對於上面提到的這些字符,若是不通過編碼,那麼它們有可能會形成Url語義的不一樣。所以對於Url而言,只有普通英文字符和數字,特殊字符$-_.+!*'()還有保留字符,才能出如今未經編碼的Url之中。其餘字符均須要通過編碼以後才能出如今Url中。
可是因爲歷史緣由,目前尚存在一些不標準的編碼實現。例如對於~符號,雖然RFC3986文檔規定,對於波浪符號~,不須要進行Url編碼,可是仍是有不少老的網關或者傳輸代理會。
3、如何對Url中的非法字符進行編碼
Url編碼一般也被稱爲百分號編碼(Url Encoding,also known as percent-encoding),是由於它的編碼方式很是簡單,使用%百分號加上兩位的字符——0123456789ABCDEF——表明一個字節的十六進制形式。Url編碼默認使用的字符集是US-ASCII。例如a在US-ASCII碼中對應的字節是0x61,那麼Url編碼以後獲得的就是%61,咱們在地址欄上輸入http://g.cn/search?q=%61%62%63,實際上就等同於在google上搜索abc了。又如@符號在ASCII字符集中對應的字節爲0x40,通過Url編碼以後獲得的是%40。
對於非ASCII字符,須要使用ASCII字符集的超集進行編碼獲得相應的字節,而後對每一個字節執行百分號編碼。對於Unicode字符,RFC文檔建議使用utf-8對其進行編碼獲得相應的字節,而後對每一個字節執行百分號編碼。如"中文"使用UTF-8字符集獲得的字節爲0xE4 0xB8 0xAD 0xE6 0x96 0x87,通過Url編碼以後獲得"%E4%B8%AD%E6%96%87"。
若是某個字節對應着ASCII字符集中的某個非保留字符,則此字節無需使用百分號表示。例如"Url編碼",使用UTF-8編碼獲得的字節是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,因爲前三個字節對應着ASCII中的非保留字符"Url",所以這三個字節能夠用非保留字符"Url"表示。最終的Url編碼能夠簡化成"Url%E7%BC%96%E7%A0%81" ,固然,若是你用"%55%72%6C%E7%BC%96%E7%A0%81"也是能夠的。
列舉帶有特殊字符的參數替換成另外一些代替的參數,以下所示
字符 - URL編碼值
空格 - %20 (URL中的空格能夠用+號或者編碼值表示)
" - %22
# - %23
% - %25
& - %26
( - %28
) - %29
+ - %2B
, - %2C
/ - %2F
: - %3A
; - %3B
< - %3C
= - %3D
> - %3E
? - %3F
@ - %40
\ - %5C
| - %7C
{ - %7B
} - %7D
4、具體編碼處理方法
用URLEncode先對你原始url作個編碼,而後使用編碼後的String。
encodeURIComponent(JSON.stringify(files)) 加一下encodeURIComponen 處理便可。
web端:Javascript的escape(),encodeURIComponent(),encodeURI ()這三個函數進行URL編碼,防止特殊字符接收不到。
Java代碼:
5、案例
在將tomcat升級到7.0.81版後,發現系統的有些功能不能使用了,查詢日誌發現是有些地址直接被tomcat認爲存在不合法字符,返回HTTP 400錯誤響應,錯入信息以下:
一、緣由分析
經瞭解,這個問題是高版本tomcat中的新特性:就是嚴格按照 RFC 3986規範進行訪問解析,而 RFC 3986規範定義了Url中只容許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字符以及全部保留字符(RFC3986中指定了如下字符爲保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。而咱們的系統在經過地址傳參時,在url中傳了一段json,傳入的參數中有"{"不在RFC3986中的保留字段中,因此會報這個錯。
根據(https://bz.apache.org/bugzilla/show_bug.cgi?id=60594) ,從如下版本開始,有配置項可以關閉/配置這個行爲:
8.5.x系列的:8.5.12 onwards
8.0.x系列的:8.0.42 onwards
7.0.x系列的:7.0.76 onwards
二、處理方法
.../conf/catalina.properties中,找到最後註釋掉的一行 #tomcat.util.http.parser.HttpParser.requestTargetAllow=| ,改爲tomcat.util.http.parser.HttpParser.requestTargetAllow=|{},表示把{}放行
Ps:固然也能夠在參數傳遞前對URL先編碼。