[故障引起的故事]URL中带加号(+)的处理
問題起因:??
????客戶訂購了一關鍵字為"e+h?變送器"?, 在首頁推薦廣告中,會根據用戶在search?搜索過的關鍵字進行一個匹配投放。技術實現是UED?通過JS?獲取cookie?中的h_keys?內容,拼裝到?http://xxxxx/advert/ctp_advert.htm?num=4&keyword=?{keyword}?。 這里取出來對應的cookie?信息為中文,最后通過一個ajax?發起一個GET請求。
????所以針對最后的請求是:http://xxxxxx/advert/ctp_advert.htm?num=?4&keyword=e+h?變送器。 而在服務端接受到對應的請求參數時,發現參數為:e h?變送器,?+?號沒了?!〕醪綉岩筛?#xff35;RL規范相關,需要進行url encode。
問題分析:?
????查了下JS encode?的相關內容, 總于發現+?號的秘密。
?? html?中因為一些非標準的做法,將+?等同于空格進行處理?(當Html?的表單被提交時, 每個表單域都會被Url?編碼之后才在被發送。由于歷史的原因,表單使用的Url?編碼實現并不符合最新的標準。例如對于空格使用 的編碼并不是%20?,而是+?號,如果表單使用的是Post?方法提交的,我們可以在HTTP?頭中看到有一個Content-Type?的header?,值為?application/x-www-form-urlencoded?,大部分應用程序均能處理這種非標準實現的Url?編碼)。
????在搜索引擎中做了下嘗試:
??? keyword =? e h?變送器? , url =?http: //www.google.cn/search?hl=zh-CN&newwindow=1&q=e+h變送器??? (?空格被轉化為+?號)
??? keyword = e+ h?變送器?, url =?http: //www.google.cn/search?hl=zh-CN&newwindow=1&q=e%2Bh變送器?? (+?號被進行了轉義為%2B?,程序才能正常處理)
???
問題解決:
思路1:
??? 1.??要想正常傳輸+?號而不被轉義為空格,需要進行進行編碼為%2B?。查了下幾個編碼函數,發現只有encodeURIComponent?才會對+?號進行編碼處理。
??? 2. encodeURIComponent?默認為采用UTF-8?字符集,理論上只需要在原先的請求中添加_input_charset=utf-8(由?pipeline?中的SetLocaleValve?進行解析)?,就可以得到正確的?e+h?變送器。?
????
????在實施過程中,發現結果并不是預期的那樣。 客戶端通過js encode?后,在服務端解析后一直是亂碼。 查了下byte?,發現服務端一直是用GBK?在進行解析, 針對變送器的UTF-8?編碼的byte?為{-27,-113,-104,-23,-128,-127}?,客戶端用GBK?解析后變為{-27.-113.- 104.-23,-63,-63}?,針對最后兩byte?因為字符不可見,導致全部被替換為-63?。網上查了下,針對?utf-8 -> gbk -> utf-8?在一定情況下就會出現該問題(http://lingqi1818.iteye.com/blog/348953?)?。
思路2?:?
????繼續追查對應的_input_charset=utf-8?未生效的原因,DEBUG?看到在SetLocaleValve?中的確設置了request.setCharsetEncoding?為utf-8?。初步懷疑是否跟jboss server?的配置有關,查了下跟URIEncoding?和useBodyEncodingForURI?設置有關。 目前公司所使用的jboss?為4.05?,對應俄tomact?配置中只指定了對應的URIEncoding=GBK?。正因為這樣,導致設置的_input_charset?針對GBK?的提交沒有效果?,還是按照GBK?進行解析。
??? 1.??考慮將請求由GET?換成POST?, 這樣就可以使用_input_charset?
????但在實施過程中,和UED?溝通過程,針對POST?的會引起一個跨域請求的問題。此方案又只能做罷
思路3?(?實踐成功)?:?
????
??? 1.? UED?進行偽url encode?的實現?,?將+?號進行%2B?的編碼。 因為目前JS?中沒有現成的函數,這里只是通過replace(/\+/g, '%2B')?進行了轉化。
總 結
針對+?號的處理,針對不同的業務場景需要不同的處理方案,描述下幾種場景:
1.?非Ajax?請求
????可以直接使用Form?表單的?GET ,POST?的urlencode?協議,自動實現+ => %2B?的轉化
2.? Ajax?請求
??? * GET?請求?:?很無奈,只能使用方案3?,人為進行+?號轉化。
??? * POST?請求(?同一應用,非跨域請 求) :??使用encodeURIComponent +? _input_charset=utf-8?指定編碼進行處理。
ps:?前面提的這幾種方案,都是基于+?號是正常的業務場景進行考慮。同時我們也可以從業務層面進行一個梳理,+?號處理是否有其必要性,能從業務數據入口直接規避 那就最好了。?
?
背景知識:
URIEncoding?和useBodyEncodingForURI
????對于URL?提交的數據和表單中GET?方式提交的數據,在接收數據的JSP?中設置request.setCharacterEncoding參數是不行的, 因為在Tomcat5.0?中,默認情況下使用ISO- 8859-1?對URL?提交的數據和表單中GET?方式提交的數據進行重新編碼(解碼),而不使用該參數對URL?提交的數據和表單中GET?方式提交的數據進行 重新編碼(解碼)。要解決該問題,應該在Tomcat?的配置文件的Connector?標簽中設置useBodyEncodingForURI?或者URIEncoding?屬性,其中useBodyEncodingForURI?參數表示是否用?request.setCharacterEncoding?參數對URL提交的數據和表單中GET?方式提交的數據進行重新編碼?,在默認情 況下,該參數為false?(Tomcat4.0?中該參數默認為true?);?URIEncoding?參數 指定對所有GET?方式請求(包括URL?提交的數據和表單中GET?方式提交的數據)進行統一的重新編碼(解碼)的編碼?。?URIEncoding?和useBodyEncodingForURI?區別是,URIEncoding?是對所有GET?方式的請求的數據進行統一的重新編碼 (解碼),而useBodyEncodingForURI?則是根據響應該請求的頁面的request.setCharacterEncoding?參數對數 據進行的重新編碼(解碼),不同的頁面可以有不同的重新編碼(解碼)的編碼。所以對于URL?提交的數據和表單中GET?方式提交的數據,可以修改?URIEncoding?參數為瀏覽器編碼或者修改useBodyEncodingForURI?為true?,并且在獲得數據的JSP?頁面中?request.setCharacterEncoding參數設置成瀏覽器編碼。
為什么需要Url?編碼
1.? Url?中有些字符會引起歧義?, =,&?號等
2.? Url?的編碼格式采用的是ASCII?碼,而不是Unicode?,這也就是說你不能在Url?中包含任何非ASCII?字符,例如中文
哪些字符需要編碼
RFC3986?文檔規定,Url?中只允許包含英文字母(a-zA-Z?)、數字(0-9?)、-_.~4?個特殊字符以及所有保留字符。
Url?可以劃分成若干個組件,協議、主機、路徑等。RFC3986?中指定了以下字符為保留字符: ! * ' ( ) ; : @ & =+?$ , / ? # [ ]
如何對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?。
Javascript?中的escape,encodeURI?和encodeURIComponent?的區別?
Javascript?中提供了3?對函數用來對Url?編碼以得到合法的Url?,它們分別是escape / unescape,encodeURI / decodeURI?和encodeURIComponent / decodeURIComponent?。解碼和編碼的過程是可逆的.
兼容性不同?
escape?函數是從Javascript1.0?的時候就存在了,其他兩個函數是在Javascript1.5?才引入的。但是由于Javascript1.5?已經非常普及了,所以實際上使用encodeURI?和encodeURIComponent?并不會有什么兼容性問題。
對Unicode?字符的編碼方式不同?
這三個函數對于ASCII?字符的編碼方式相同,均是使用百分號+?兩位十六進制字符來表示。但是對于Unicode?字符,escape?的編碼方式是% uxxxx?,其中的xxxx?是用來表示unicode?字符的4?位十六進制字符。這種方式已經被W3C?廢棄了。但是在ECMA-262?標準中仍然保留著?escape?的這種編碼語法。encodeURI?和encodeURIComponent?則使用UTF-8?對非ASCII?字符進行編碼,然后再進行百分號 編碼。這是RFC?推薦的。因此建議盡可能的使用這兩個函數替代escape?進行編碼。
適用場合不同?
encodeURI?被用作對一個完整的URI?進行編碼,而encodeURIComponent?被用作對URI?的一個組件進行編碼。
安全字符不同?
escape?(69?個)?*/@+-._0-9a-zA-Z???
encodeURI?(82?個)?!#$&'()*+,/:;=?@-._~0-9a-zA-Z??
encodeURIComponent?(71?個)?!'()*-._~0-9a-zA-Z???(?注意+?號未在其安全字符里)
其他和Url?編碼相關的問題
對于包含中文的Url?的處理問題,不同瀏覽器有不同的表現。例如對于IE?,如果你勾選了高級設置“?總是以UTF-8發送Url”?,那么Url?中的路徑部分 的中文會使用UTF-8?進行Url?編碼之后發送給服務端,而查詢參數中的中文部分使用系統默認字符集進行Url?編碼。為了保證最大互操作性,建議所有放到?Url?中的組件全部顯式指定某個字符集進行Url?編碼,而不依賴于瀏覽器的默認實現。
另外,很多HTTP?監視工具或者瀏覽器地址欄等在顯示Url?的時候會自動將Url?進行一次解碼(使用UTF-8?字符集),這就是為什么當你在?Firefox?中訪問Google?搜索中文的時候,地址欄顯示的Url?包含中文的緣故。但實際上發送給服務端的原始Url?還是經過編碼的。你可以在地址欄 上使用Javascript?訪問location.href?就可以看出來了。在研究Url?編解碼的時候千萬別被這些假象給迷惑了。
原文鏈接:http://agapple.iteye.com/blog/773061
轉載于:https://blog.51cto.com/1799919/1557707
總結
以上是生活随笔為你收集整理的[故障引起的故事]URL中带加号(+)的处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中JTextPane使输出字符到
- 下一篇: ] ssh登录慢的原因