java學習-http中get請求的非ascii引數如何編碼解碼探討
# 背景:
看著別人專案程式碼看到一個PathUtils工具類,
裡面只有一個方法,String rebuild(String Path),將路徑進行URLDecoder.decode解碼,避免路徑中因為中文亂碼導致程式異常
上面的方法的用處是,獲取到專案配置檔案的路徑,通過 rebuild 方法返回解碼後的路徑。
# 疑惑:
由於我不清楚Path變數是怎麼樣的情況,為什麼要經過rebuild方法過濾一遍
就想測試下,如果是正常中文進行解碼,解碼後的字串還是一樣的嗎?
String newPath = "Keywords=溼答答"; try { newPath= URLDecoder.decode(newPath, "UTF-8"); System.out.println(newPath); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); }
結果中文沒有發生變化。
接著我檢視的 URLDecoder的decode方法, + 號和 % 開頭的字串才會進行解碼
note:這裡的編碼解碼也稱 %百分號編碼解碼
# 深入學習:
接著,用百度搜索的下 “urldecoder 編碼和解碼”
發現url編碼解碼主要是應用於傳送 http 的 get 請求時,對特定字串進行編碼,後臺伺服器會對get請求的url進行解碼,以保證網路傳輸過程中資料的正常。
看到一篇文章 不同瀏覽器中URL的編碼方式
不同瀏覽器對編碼字元的編碼方式是不同的,
如IE瀏覽器可以設定編碼的方式
可以設定是否傳送utf-8格式的url
瀏覽器對URL編碼方式不一樣可能會導致我們後臺獲取到的資料是錯誤的。
瀏覽器編碼方式有gbk,utf-8,等等,
假設:瀏覽器使用gbk的編碼方式編碼中文引數。我們後臺伺服器接收到後會進行utf-8解碼,因為解碼方式不一樣,就導致我們獲取到的引數是亂碼的
為了避免這個問題我們需要自己對get請求的引數進行url編碼。
為什麼要自己主動對引數進行編碼呢,需要先大概看下編碼解碼過程
注意:url編碼解碼也稱 %百分號編碼解碼
編碼過程:
字母,特殊使用者字元(/,:@-_.等。即斜槓,逗號,點,冒號,橫線,下劃線等)
會被直接跳過,不會進行編碼處理,
其他的所有字元都要經過%xx編碼處理。
encodeURI不編碼字元有82個:!,#,$,&,',(,),*,+,,,-,.,/,:,;,=,?,@,_,~,0-9,a-z,A-Z
編碼方法很簡單,在該位元組ascii碼的的16進位制字元前面加%
如 空格字元,ascii碼是32,對應16進位制是'20',那麼urlencode編碼結果是 %20
由於JavaScript使用的是Unicode編碼,也就是utf-8編碼,所以編碼函式也是使用utf-8編碼,
所以js的encodeURI函式,編碼中文,‘愛’ 是三個位元組,編碼後 %e7%88%b1 ,這3個十六進位制就代表,愛
解碼過程:
解碼是編碼的逆向,對匹配到的百分號編碼進行反向解碼,字母和特殊字元也會被跳過。java中會對+號字元進行特殊處理,直接用空格替換。
上面的編碼和解碼有一個值得注意的地方,瀏覽器不會對 + 號進行編碼,而tomcat或jetty伺服器會將這個加號使用空格替換。
如下面的get請求
http://localhost:8080/api/test?aa=zhang+san&p2=18
我們java中使用request.getParameter("aa")方法獲取到的aa引數的值是zhang san
+ 號被替換成的空格
這是一種情況,使用者輸入,跟我們獲取到的資料不一致
還有一種情況,伺服器是以 & 符號進行分割引數的,如果我們把上面+號替換成&
http://localhost:8080/api/test?aa=zhang&san&p2=18
我們獲取到aa的值是zhang
伺服器會認為這個get請求有三個引數,以 & 為分隔符
分別是
aa=zhang
san=
p2=18
為了避免以上問題,我們都不應該讓瀏覽器對引數進行編碼,而是我們自己做編碼