在開發網站的過程中,post和get是常見常用的兩個方法,關于這兩個方法的詳細解釋,請列為閱讀這篇文章:[《HTTP POST GET 本質區別詳解》](https://github.com/qiwsir/ITArticles/blob/master/Tornado/DifferenceHttpGetPost.md),這篇文章前面已經推薦閱讀了,可以這么說,如果看官沒有搞明白get和post,也可以寫出web程序,但是,只要遇到“但是”,就說明另有乾坤,但是如果看官要對這方面有深入理解,并且將來能上一個檔次,是必須了解的。這就如同你要練習辟邪劍譜中的劍法,不自宮,也可以練,但是無法突破某個極限,岳不群也不傻,最終他要成為超一流,就不惜按照劍譜中開篇所說“欲練神功,揮刀自宮”,“神功”是需要“自宮”為前提,否則,練出來的不是“神功”,無法問鼎江湖。
特別提醒,看官不要自宮,因為本教程不是辟邪劍譜,也不是葵花寶典,撰寫本課程的人更是生理健全者。若看官自宮了,責任自負,與本作者無關。直到目前,科學上尚未有證實或證偽自宮和寫程序之間是否存在某種因果關系。所以提醒看官慎重行事。
還是扯回來,看下面的代碼先:
~~~
#!/usr/bin/env python
#coding:utf-8
import textwrap
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8000, help="Please send email to me", type=int)
class ReverseHandler(tornado.web.RequestHandler):
def get(self, input_word):
self.write(input_word[::-1])
class WrapHandler(tornado.web.RequestHandler):
def post(self):
text = self.get_argument("text")
width = self.get_argument("width", 40)
self.write(textwrap.fill(text, width))
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers = [
(r"/reverse/(\w+)", ReverseHandler),
(r"/wrap", WrapHandler)
]
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
~~~
這段代碼跟上一講的代碼相比,基本結構是一樣的,但是在程序主體中,這次寫了兩個類`ReverseHandler`和`WrapHandler`,這兩個類中分別有兩個方法get()和post()。在`tornado.web.Application()`實例化中,handlers的參數值分別設置了不同路徑對應這兩個類。
其它方面跟上一講的代碼一樣。
把上述代碼的文件,存到某個目錄下,我給他取名為:request_url.py,名字看官也可以自己定。然后進入該目錄,運行:`python request_url.py`,就將這個tornado框架的網站以端口8000發布了。
打開網頁,在瀏覽器中輸入:`http://localhost:8000/reverse/qiwsirpython`
界面上輸出什么結果?
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/30801.png)
還可以在命令終端,用下面方式調試,跟在網頁上輸出是等同效果。
~~~
qw@qw-Latitude-E4300:~$ curl http://localhost:8000/reverse/qiwsirpython
nohtypriswiq
~~~
再看另外一個路徑,看官運行的是否是下面的結果呢?
~~~
qw@qw-Latitude-E4300:~$ curl http://localhost:8000/wrap -d text=I+love+Python+programming+and+I+am+writing+python+lessons+on+line
I love Python programming and I am
writing python lessons on line
~~~
調試通過,就開始分析其中的奧妙。
## get()
在ReverseHandler類中,定義了這個方法。
~~~
class ReverseHandler(tornado.web.RequestHandler):
def get(self, input_word):
self.write(input_word[::-1])
~~~
這個get()方法要和下面Application實例化中的路徑:
~~~
(r"/reverse/(\w+)", ReverseHandler),
~~~
關聯起來看。
首先看路徑設置:`r"/reverse/(\w+)"`,這個路徑的意思就是可以在瀏覽器的url中輸入:http://localhost:8000/reverse/dddd,這個樣子的地址,注意路徑中的`(\w+)`,是正則表達式,在reverse/的后面可以輸入一個或者多個包括下劃線的任何單詞字符。也就是dddd可以更換為任何其它字母或者下劃線,一個或者多個均可以。
在URL中輸入的這個地址,就被ReverseHandler類中的get()方法接收,這就是`(r"/reverse/(\w+)", ReverseHandler)`之含義了。那么,ReverseHandler中的get()方法如何接收url中傳遞過來的信息呢?
前文已經說過,在`def get(self, input_word)`中,self參數在類實例化后對應的是tornado.web.RequestHandler,另外一個參數input_word用來接收來自url的信息,但是它只接收所設置的路徑尾部數據,也就是路徑`r"/reverse/(\w+)"`中reverse后面的第一個分割符號“/”之后的內容,都被input_word接收過來,即正則表達式的內容。
input_word接收過來的對象,是什么類型呢?猜測一下,從前面程序的運行結果看,肯定是某種序列類型的對象。具體是哪種呢?可以實驗。
將get方法修改為:
~~~
def get(self, input_word):
input_type = type(input_word)
self.write("%s"%input_type)
~~~
再運行程序,打印出來的是:
~~~
qw@qw-Latitude-E4300:~$ curl http://localhost:8000/reverse/qiwei
<type 'unicode'>
~~~
這說明,get()方法通過URL接收到的數據類型是unicode編碼的字符,即字符串。
原來類方法中的`self.write(input_word[::-1])`含義是,將原來的字符串倒置,并返回該數據到客戶端(如頁面)。
~~~
>>> a = "python,laoqi"
>>> a[::-1]
'iqoal,nohtyp'
>>> b = [1,2,3,4]
>>> b[::-1]
[4, 3, 2, 1]
>>> c = ("a","b","c")
>>> c[::-1]
('c', 'b', 'a')
~~~
這是一種將序列類型對象倒置的一種方法。
總結一下:get()通過第二個參數,獲得已經設置的顯示路徑中最后一個/后面的數據,并且為unincode編碼的字符。
這種方式通過URL得到有關數據,也就是說在URL中,只需要以`http://localhost/aaa/bbb/ccc`的形式來顯示路徑即可。看官是否注意到,有的網站是這么顯示的:`http://localhost/aaa?name=Tom&&?age=25`,這其實是兩種不同的規范也好、方法也罷的東西,前者更接近時下流行的REST規范,可能看官聽說過MVC吧,我聽不少的公司都強調網站要符合MVC規范,殊不知,更流行的是REST了。那么到底那個好呢?我的觀點:It depends.如果有興趣,請閱讀:[《理解本真的REST架構風格》](https://github.com/qiwsir/ITArticles/blob/master/Tornado/understandREST.md),對REST了解一二。
## post()方法
post()也是web上常用的方法,在本例中,該方法寫在了WrapHandler類中:
~~~
class WrapHandler(tornado.web.RequestHandler):
def post(self):
text = self.get_argument("text")
width = self.get_argument("width", 40)
self.write(textwrap.fill(text, width))
~~~
對應的Application類路徑:
~~~
(r"/wrap", WrapHandler)
~~~
但是,看官要注意,post()無法從URL中獲得數據。這是跟get()方法非常不一樣的。關于get和post之間的區別,請看官點擊[《HTTP POST GET 本質區別詳解》](https://github.com/qiwsir/ITArticles/blob/master/Tornado/DifferenceHttpGetPost.md)閱讀。
客戶端的數據通過post方法發送到服務器,這個內在過程就是由所謂HTTP協議完成,不用去管它,因為現在我們只是研究應用層,不去深入網絡協議的層面。看官可以有這樣的以為:怎么傳的數據,但是我也可以不講,就算我也不會吧。不過,如果看官非要了解,請問google大神。
我要解釋的是,post()方法怎么接收到客戶端傳過來的數據。
因為post不能從URL中得到數據,所以就不能用類似的方式在網頁的url中輸入要傳給它的數據了,只能這樣來測試:
~~~
qw@qw-Latitude-E4300:~$ curl http://localhost:8000/wrap -d text=I+love+Python+programming+and+I+am+writing+python+lessons+on+line
I love Python programming and I am
writing python lessons on line
~~~
請看官注意,URL依然是`http://localhost:8000/wrap`,后面的部分`-d text=...`,就是向這個地址對應的類WrapHandler中的post方法傳送相應的數據,這個數據被`tornado.web.RequestHandler`中的get_arugment()方法獲得,也就是通過`text=self.get_argument("text")`得到傳過來的對象,并賦值給text。
這里需要提醒看官注意,`self.get_argument("text")`的參數中,是`"text"`,就意味著,傳入數據的時候,需要用text這個變量,即必須寫成`text=...`。如果`self.get_argument("word")`,那么就應該是`word=...`方式傳入數據了。
看官此時是否已經曉得,get_argument()在post方法中,能夠獲得客戶端傳過來的數據,當然是unicode編碼的。得到這個數據之后,就可以按照自己的需要進行操作了。
下一句`width = self.get_argumen("width", 40)`是要返回一個對象,這個對象約定變量為40,并將它用在下面的`textwrap.fill(text, width)`中。這里并沒有什么特別支出,也可以寫成`width = 40`,其實就是給textwrap.fill()提供參數罷了。關于textwrap模塊中的fill方法,可以用help命令來看看。
~~~
>>> import textwrap
>>> help(textwrap.fill)
Help on function fill in module textwrap:
fill(text, width=70, **kwargs)
Fill a single paragraph of text, returning a new string.
Reformat the single paragraph in 'text' to fit in lines of no more
than 'width' columns, and return a new string containing the entire
wrapped paragraph. As with wrap(), tabs are expanded and other
whitespace characters converted to space. See TextWrapper class for
available keyword args to customize wrapping behaviour.
~~~
## [](https://github.com/qiwsir/ITArticles/blob/master/BasicPython/308.md#簡要總結requesthandler)簡要總結RequestHandler
RequestHandler就是請求處理程序的方法,從上面的流程中,可以簡要地初步地認為(深奧的東西還不少,這里只能是簡要地初步地膚淺地,隨著學習的深入會一點點深入地):
* 通過`self.write()`向客戶端返回數據
* get()中,以一個參數從URL路徑末尾獲取數據,特別提醒看官,這是在本講的例子中,get()方法中,用第二個參數獲得url數據。在[上一講](https://github.com/qiwsir/ITArticles/blob/master/BasicPython/307.md)中,同樣是get()方法,用到了`greeting = self.get_argument('greeting', 'Hello')`,于是不需要在get()中另外寫參數,只需要通過"greeting"就可以得到URL中的數據,不過這時候的url應該寫成`http://localhost:8000/?greeting=PYTHON`的樣式,于是字符傳'PYTHON'就能夠讓get()中的`self.get_argument('greeting','Hello')`獲得,如果沒有,就是'Hello'。
* post()中,以`self.argument("text")`的形式得到`text`為標簽提交的數據。
get和post是http中用的最多的方法啦。此外,Tornado也還支持其它的HTTP請求,如:PUT、DELETE、HEAD、OPTIONS。在具體編程的時候,如果看官用到,可以搜索,一般用的不多。
最后交代一句,get和post方法,由于一個是通過URL得到數據,另外一個不是,所以,他們可以寫到同一個類中,彼此互不干擾。
還要說明,我在這部分參考了一本書的講授內容,特別是其中的代碼例子,這本書就是[《Introduction to Tornado》](http://it-ebooks.info/book/687/)
- 第零部分 獨上高樓,望盡天涯路
- 嘮叨一些關于Python的事情
- 為什么要開設本欄目
- 第一部分 積小流,至江海
- Python環境安裝
- 集成開發環境(IDE)
- 數的類型和四則運算
- 啰嗦的除法
- 開始真正編程
- 初識永遠強大的函數
- 玩轉字符串(1):基本概念、字符轉義、字符串連接、變量與字符串關系
- 玩轉字符串(2)
- 玩轉字符串(3)
- 眼花繚亂的運算符
- 從if開始語句的征程
- 一個免費的實驗室
- 有容乃大的list(1)
- 有容乃大的list(2)
- 有容乃大的list(3)
- 有容乃大的list(4)
- list和str比較
- 畫圈還不簡單嗎
- 再深點,更懂list
- 字典,你還記得嗎?
- 字典的操作方法
- 有點簡約的元組
- 一二三,集合了
- 集合的關系
- Python數據類型總結
- 深入變量和引用對象
- 賦值,簡單也不簡單
- 坑爹的字符編碼
- 做一個小游戲
- 不要紅頭文件(1): open, write, close
- 不要紅頭文件(2): os.stat, closed, mode, read, readlines, readline
- 第二部分 窮千里目,上一層樓
- 正規地說一句話
- print能干的事情
- 從格式化表達式到方法
- 復習if語句
- 用while來循環
- 難以想象的for
- 關于循環的小伎倆
- 讓人歡喜讓人憂的迭代
- 大話題小函數(1)
- 大話題小函數(2)
- python文檔
- 重回函數
- 變量和參數
- 總結參數的傳遞
- 傳說中的函數條規
- 關于類的基本認識
- 編寫類之一創建實例
- 編寫類之二方法
- 編寫類之三子類
- 編寫類之四再論繼承
- 命名空間
- 類的細節
- Import 模塊
- 模塊的加載
- 私有和專有
- 折騰一下目錄: os.path.<attribute>
- 第三部分 昨夜西風,亭臺誰登
- 網站的結構:網站組成、MySQL數據庫的安裝和配置、MySQL的運行
- 通過Python連接數據庫:安裝python-MySQLdb,連接MySQL
- 用Pyton操作數據庫(1):建立連接和游標,并insert and commit
- 用Python操作數據庫(2)
- 用Python操作數據庫(3)
- python開發框架:框架介紹、Tornado安裝
- Hello,第一個網頁分析:tornado網站的基本結構剖析:improt模塊、RequestHandler, HTTPServer, Application, IOLoop
- 實例分析get和post:get()通過URL得到數據和post()通過get_argument()獲取數據
- 問候世界:利用GAE建立tornado框架網站
- 使用表單和模板:tornado模板self.render和模板變量傳遞
- 模板中的語法:tornado模板中的for,if,set等語法
- 靜態文件以及一個項目框架
- 模板轉義
- 第四部分 暮然回首,燈火闌珊處
- requests庫
- 比較json/dictionary的庫
- defaultdict 模塊和 namedtuple 模塊
- 第五部分 Python備忘錄
- 基本的(字面量)值
- 運算符
- 常用的內建函數
- 擴展閱讀(來自網絡文章)
- 人生苦短,我用Python