Python-Web框架-get_argument方法
目錄概覽
-
1.使用get_argument獲取url query參數
-
2.為何get_argument不區分POST與GET?
-
3.get_argument返回unicode數據類型的問題
1.使用get_argument獲取url query參數
Tornado的每個請求處理程序,我們叫做handler,handler里可以自定義自己的處理程序,其實也就是重寫方法,如post,get,get_current_user,send_error等等,這里我們只講get和post的自定義。
我們都知道,在Tornado里,獲得用戶的輸入,都是一個get_argument搞定,似乎很順理成章:
def post(self):
nowamagic = self.get_argument('nowamagic')
self.write( nowamagic )
先介紹一點基本知識。我們來看看這么一個URL:http://www.nowamagic.net/academy/detail/13321002?page=1#comment
import urlparse
urlparse.urlparse('http://www.nowamagic.net/academy/detail/13321002?page=1#comment')
ParseResult(scheme='http', netloc='www.nowamagic.net', path='/academy/detail/13321002', params='', query='page=1', fragment='comment')
url由scheme(協議),netloc(主機),path(路徑),params(最后路徑的參數),query(查詢字段),fragment(錨)組成。
下面我們要獲取URL里的GET參數,也就是獲取url query中的參數,怎么辦呢?
對於單一的值,在get和post中調用self.get_argument("name", "default")。
對於多選的值,調用self.get_arguments("name")即可。
get_argument方法可以設置默認值,也可以設置是否刪除兩端的空格。
源碼聲明如下:
get_argument(self, name, default=_ARG_DEFAULT, strip=True)
get_arguments(self, name, strip=True)
2.為何get_argument不區分POST與GET?
Tornado的get_argument有點類似PHP的 $ _REQUEST,是不區分GET與POST的。而且Tornado好像是沒有PHP里的$ _GET,$ _POST這樣的區分獲取get數據與post數據的方法。為什么會這樣么?
URL的query string還是x-www-form-encode的數據可以按key/value方式來解析,其實是一種約定俗成的規矩。甚至表單POST的編碼格式都是和GET的query string編碼是一樣的。CGI的實現中也只用了一套代碼來處理。就說兩種方法實際上在做同一件事情。
而同時提供key/value的query string和x-www-form-encode的POST數據,也不違反任何協議和標准。
其次,通常當你要提交key/value數據的時候,目的是一致的。POST只不過允許你提交更多的數據而已。為什么要混用兩套東西呢?
tornado做的,只不過是提供接口提高最常見場景的編碼效率。如果應用場景比較特殊,可以自行解析request.body, request.url,獲取原始的數據進行處理。
從安全角度來說,在Tornado中,一個RequestHandler中,處理GET和POST是兩個不同的函數,這是一個很關鍵的因素。
對於某些Framework(比如Zend Framework),Model不區分GET和POST方法,換句話說,一個URL Patten不管是通過POST還是GET來訪問,處理函數都是同一個,所以Zend的getParam方法就向程序員提供了數據來源的選擇。而且這對於Zend Framework程序的安全也是至關重要。
-
對於GET請求,沒什么好說的,因為GET請求的數據來源只有query string一條路,所以指定數據來源是沒有意義的。
-
對於POST請求,XSRF攻擊者的確可以將本來應該寫在x-www-form-encode里的數據轉移到query string里,但是這么做毫無意義。因為這樣做會使請求變為get函數來處理。攻擊自然會失敗。
所以,Tornado的這種做法是有道理的,而不是簡單的為了提高編碼效率。畢竟,編碼效率的提高也必須建立在保證安全的基礎上。
3. get_argument返回unicode數據類型的問題
在 Tornado 里,self.get_argument返回的數據類型為unicode:
chars = self.get_argument('chars')
self.write( str(type(chars)) )
# 輸出
# <type 'unicode'>
get_argument在獲取數據的時候,會進行decode("utf-8")操作,因為get_argument最終調用了tornado.escape下面的to_unicode方法,也就是argument會通過decode("utf-8")來轉成unicode:
def to_unicode(value):
"""
Converts a string argument to a unicode string.
If the argument is already a unicode string or None, it is returned
unchanged. Otherwise it must be a byte string and is decoded as utf8.
"""
if isinstance(value, _TO_UNICODE_TYPES):
return value
assert isinstance(value, bytes)
return value.decode("utf-8")
# to_unicode was previously named _unicode not because it was private,
# but to avoid conflicts with the built-in unicode() function/type
_unicode = to_unicode
get_argument獲取數據之后一般需要先使用u.encode('utf-8')轉換成string類型后才能使用。
如果用get_argument無法獲取數據,可以用更加原始的方法通過self.request.arguments獲取GET或者POST的所有參數字典,這個字典是未經過decode處理的原生參數,每個參數都是字典里面的一項,主要每個參數對應的項都是一個列表。