http請求(GET/POST)時,url/參數編碼的過程分析

http請求(GET/POST)時,url/參數編碼的過程分析

這個實驗,是在採用ssm框架的基礎上演示的。

在前端向後端發出http請求時,有時候當咱們採用GET方式時,參數會被編碼在url後面。那麼這個url是如何編碼解碼的呢?前端

http請求的發出,以及編碼過程

下面在chrome瀏覽器和postman下模擬請求,用fiddler來監控請求發出信息。chrome

chrome遊覽器地址輸入:
clipboard.pngjson

這個路徑是手動輸入的,黑色線是url,黃色線是uri,綠色線是queryString。這時F12,而後咱們路徑按下回車後端

chrome地址數組

clipboard.png

chrome監控瀏覽器

clipboard.png

fiddler監控tomcat

clipboard.png

咱們關注chrome控制檯和fiddler的狀況,能夠發現,chrome發出這個http請求的時候,對查詢參數進行了編碼。咱們在網站(https://www.bejson.com/conver... 進行Hex轉字符的操做,能夠發現:中文字符被編碼成16進制數,並且每一個字節(byte)的16進制數前都被瀏覽器加上了一個%。(下圖中,20E8B083這4個字節對應「調」,E4BC98這3個字節對應「優」)服務器

clipboard.png

瀏覽器編碼url的風格: 到這裏,可能你有點迷惑了。我來解釋一下,根據URL的編碼規範,瀏覽器會把URL中的非ASCII字符按照某種編碼格式(chrome是utf-8)編碼成byte數組後,轉成16進制數字,而後在每一個16進制數字前加上%分隔。網絡

到如今,應該清楚了瀏覽器GET傳參時的編碼過程了。值得一提的是,在實踐中,咱們最糟糕也只會在GET方式的url後面攜帶中文參數,在servletPath(也就是?前的一段)中咱們不會去用中文的,除非你自找麻煩。框架

具體的傳輸: 其實,咱們尚未講到url的傳輸。咱們要知道,在網絡世界的傳輸中,全部的信息都是以字節傳輸的(byte[]),一個http請求的全部內容都是編碼成byte數組後傳輸的,也就是0101這樣的數字。爲了方便顯示,fiddler中用Hex來表示。能夠這麼理解,上面那個url路徑只是一個初步處理後的string而已,咱們從fiddler中查看,

clipboard.png

咱們對Hex進行幾回copy查看:

clipboard.png

能夠看出,傳輸過程當中的Hex數組,就是咱們以前監控到的真正的http請求url通過了中文utf-8編碼後的路徑。

http請求的接收,以及解碼過程

需不須要設置解碼呢?

答案是確定的,手動設置一下確定是很是好的。

uri/url的解碼過程

下面咱們以tomcat爲例,當上面那一大串byte數組傳輸到服務器後,首先,tomcat會對uri部分進行解碼,這裏charset由tomcat配置文件中的<Connector URIEncoding="UTF-8"決定,不設置的話默認值爲ISO-8859-1。因爲域名和端口只會是英文,好比說:www.baidu.com,www.google.com;同時咱們上面講過,在uri部分咱們不會去用中文,咱們只會採用英文。所以,對於url這一塊,不管是採用UTF-8仍是ISO-8859-1解碼,url這部份內容都不會亂碼。到這一步,咱們服務器端就解碼獲得了localhost:8082/article/queryByTitle

queryString的解碼過程

上面,咱們知道了uri/url這一塊的內容解碼過程。下面,咱們來看看queryString這部分的解碼過程。

咱們在chrome中,F12查看http請求的詳細信息,能夠發現查詢參數被做爲parameters保存了下來。這裏,能夠告訴你們,經過GET方式發出http請求所攜帶的queryString以及經過POST方式發出http請求所攜帶的表單參數,也就是GET、POST這2種方式攜帶的參數,都會被做爲parameters保存;在服務器端經過request.getParameter()方法能夠獲取到值。

clipboard.png

下面以GET方式的queryString的解碼過程來說解。首先咱們思考一下,如何才能獲得原來的中文呢?固然是先把Hex數字使用UTF-8轉碼一次,獲得瀏覽器初步處理的參數,如:title=JVM%20%E8%B0%83%E4%BC%98,而後再對原來非ASCII字符的部分使用UTF-8轉碼一次,獲得最初值:title=JVM 調優。中文這一塊我也沒找到相關資料,我就分析一下英文的解碼過程吧。

1.英文參數的狀況

假設咱們原有的請求並不含中文參數,好比說:title=JVMoptimize 。那麼在服務器端調用request.getParameter的方法時,會先進行轉碼,而charset由http請求的header中的contentType決定,不然使用ISO-8859-1。要想使用contentType的charset,還須要把<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true" />設置爲true,注意,true只是設置queryString的解碼。到這裏,對Hex的解碼就會採用contentType的UTF-8進行解碼了,咱們就能夠還原獲得title=JVMoptimize了,而後取到JVMoptimize這個參數值。

2.中文參數的狀況

咱們再來說一講中文參數的問題,由於在chrome中,非ASCII字符會採用UTF-8先進行一次編碼;那麼其實在服務器端,咱們能夠本身思考一下。由於若是是純英文的參數,下圖是title=JVM optimize的請求,在初步處理時,空格是Hex的%20,也就是說純英文下%後面必定是20,%20表明了一個空格。而若是是中文參數,由於瀏覽器手動在每個字節前加了%,注意,這樣咱們服務器端經過%和其後面的是否跟着20就能夠知道這裏是空格仍是表明着中文參數了。

clipboard.png

queryString解碼的猜測

咱們能夠作出設想,在對queryString進行第一次轉碼以後,可能有2種基本狀況:

  • 純英文,還有空格的參數。原參數如:title=JVM optimize
    那麼第一次轉碼,會獲得:title=JVM%20optimize
  • 中文,還有空格的參數。原參數如:title=JVM 調優
    那麼第一次轉碼。會獲得:title=JVM%20%E8%B0%83%E4%BC%98

這個時候的結果就很明確了。我猜想,這時候服務器內部應該會對%進行檢測,而後作出相應的處理。下面是個人猜想:

若是檢測到%,那麼看看其後面是否跟着20?是的話,就表示這是一個空格,將其轉化(解碼)爲空格" " ;不是的話,表明這一塊將是中文字符(或其餘非ASCII字符,如日文,韓文),就把這一塊連續的%剔除,再用UTF-8轉碼,就獲得了中文字符。

上面應該是挺靠近真實狀況的解釋了,由於確定對非ASCII的解碼要進行2次,上面的依據也挺充足的。

其餘

那麼我已經對url的編碼解碼過程作了一個分析,要注意的點和須要設置的地方在文中已經提到了。對於網上常見的一個設置:request.setCharacterEncoding(charset),設不設置都無所謂了,它的做用和contentType是同樣的。

相關文章
相關標籤/搜索