1. 程式人生 > >java學習-http中get請求的非ascii引數如何編碼解碼探討

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

 

為了避免以上問題,我們都不應該讓瀏覽器對引數進行編碼,而是我們自己做編碼