1. 程式人生 > >URL中特殊符號的轉義/400 bad request錯誤

URL中特殊符號的轉義/400 bad request錯誤

django+nginx+uwsgi部署的站點訪問某個URL時發生了400 bad request的錯誤,而使用django自帶的開發版的web server時沒有遇到此問題。初步判斷是nginx或uwsgi配置問題。

網上有說是因為request header過大而nginx配置的client_header_buffer_size和large_client_header_buffers過小引起的,但就當前的狀態來看感覺不太可能。因為request header並不是特別大。至於是別的什麼原因還暫未找到,所以還是先試試看。

在nginx配置檔案nginx.conf中的http部分加入如下兩行引數:
client_header_buffer_size 16k;
large_client_header_buffers 4 64k;
nginx預設會用client_header_buffer_size這個buffer來讀取header值,如果header過大,它會使用large_client_header_buffers來讀取header值。若該值設定過小而請求頭/COOKIE過大則會報400 bad request錯誤。

調整引數重新載入配置檔案重啟uwsgi後發現問題並未解決。
經仔細檢視才發現原來是請求的URL中引數包含了特殊字元%,導致Web Server沒能夠正確解析出該URL,才報了這個錯誤。

在URL中下列字元具有特殊含義:
符號含義     如何轉義
+    URL中+號表示空格                           %2B     
空格 URL中的空格可以用+號或者編碼 %20   
/  分隔目錄和子目錄                                 %2F       
?    分隔實際的URL和引數                     %3F       
%    指定特殊字元                                    %25       
#    表示書籤                                             %23       
&    URL中指定的引數間的分隔符        %26       
=    URL中指定引數的值                        %3D 

比如sever端從提交的表單的輸入框中的值構造包含引數的URL,
若提交的內容為“pkgcr+awldb”,位址列的URL顯示為“xxx/?q=pkgcr%2Bawldb”,也即引數中q的值實際上為“pkgcr+awldb”
若提交的內容為“pkgcr awldb”,位址列的URL顯示為“xxx/?q=pkgcr+awldb”,也即引數中q的值實際上為“pkgcr awldb”
若提交的內容為“pkgcr/awldb”,位址列的URL顯示為“xxx/?q=pkgcr%2Fawldb”,也即引數中q的值實際上為“pkgcr/awldb”
若提交的內容為“pkgcr?awldb”,位址列的URL顯示為“xxx/?q=pkgcr%3Fawldb”,也即引數中q的值實際上為“pkgcr?awldb”
若提交的內容為“pkgcr%awldb”,位址列的URL顯示為“xxx/?q=pkgcr%25awldb”,也即引數中q的值實際上為“pkgcr%awldb”
若提交的內容為“pkgcr#awldb”,位址列的URL顯示為“xxx/?q=pkgcr%23awldb”,也即引數中q的值實際上為“pkgcr#awldb”
若提交的內容為“pkgcr&awldb”,位址列的URL顯示為“xxx/?q=pkgcr%26awldb”,也即引數中q的值實際上為“pkgcr&awldb”
若提交的內容為“pkgcr=awldb”,位址列的URL顯示為“xxx/?q=pkgcr%3Dawldb”,也即引數中q的值實際上為“pkgcr=awldb”

若要是直接在server端構造URL呢?比如server端的檔案中有個變數ip,值為“172.142.%”,要在server端構造一個URL供客戶端訪問,如“href=?ip={ip}&q='mysql'”(此處假定{ip}是對變數的一種引用方式),那麼我們點選這個連結會是什麼結果呢?

我們會看到,因為變數ip中包含特殊字元“%”,而“%”在URL中具有特殊含義,我們通過上述方式構造的URL相當於是“href=?ip=172.142.%&q=mysql”,web伺服器解析該URL時無法解釋%&從而導致出錯。同樣的原因,包含其他一些特殊字元時也會發生一些意想不到的問題,比如有另一個變數addr,值為“china&america”,構造的URL為“href=?addr={addr}&q=‘mysql’”,此時構建的URL相當於是“href=?addr=china&america&q=mysql”,web伺服器會把該URL中的第一個“&”後的“america”解析為另外一個引數而不是將“china&america”整體作為“addr”引數的值。

那麼如何在需要的時候在URL中包含諸如%、&、+、=等等這樣的特殊的字元呢?答案就是用相應的編碼代替特殊字元本身來構建URL。比如上例中可以先將ip的值替換為“172.142.%25”,將addr的值替換為“china%26america”,這樣構建出的URL分別為“href=?ip=172.142.%25&q=mysql”和“href=?addr=china%26america&q=‘mysql’”,這樣最終能夠將URL中的引數ip的值成功解析為“172.142.%”而將addr的值成功解析為china&america,而且不會引起其他引數解析混亂。