"Do not store up for yourselves treasures on earth, where moth and rust consume and where thieves break in and steal; but store up for yourselves treasures in heaven, where neither moth and rust consumes and where thieves do not break in and steal. For where your treasure is, there your heart will be also." (MATTHEW6:19-21)python
在開發網站的過程當中,post和get是常見經常使用的兩個方法,關於這兩個方法的詳細解釋,請列爲閱讀這篇文章:《HTTP POST GET 本質區別詳解》,這篇文章前面已經推薦閱讀了,能夠這麼說,若是看官沒有搞明白get和post,也能夠寫出web程序,可是,只要遇到「可是」,就說明另有乾坤,可是若是看官要對這方面有深刻理解,而且未來能上一個檔次,是必須瞭解的。這就如同你要練習辟邪劍譜中的劍法,不自宮,也能夠練,可是沒法突破某個極限,嶽不羣也不傻,最終他要成爲超一流,就不惜按照劍譜中開篇所說「欲練神功,揮刀自宮」,「神功」是須要「自宮」爲前提,不然,練出來的不是「神功」,沒法問鼎江湖。git
特別提醒,看官不要自宮,由於本教程不是辟邪劍譜,也不是葵花寶典,撰寫本課程的人更是生理健全者。若看官自宮了,責任自負,與本做者無關。直到目前,科學上還沒有有證明或證僞自宮和寫程序之間是否存在某種因果關係。因此提醒看官慎重行事。github
仍是扯回來,看下面的代碼先: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
服務器
界面上輸出什麼結果?網絡
還能夠在命令終端,用下面方式調試,跟在網頁上輸出是等同效果。架構
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
調試經過,就開始分析其中的奧妙。
在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架構風格》,對REST瞭解一二。
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 本質區別詳解》閱讀。
客戶端的數據經過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.
RequestHandler就是請求處理程序的方法,從上面的流程中,能夠簡要地初步地認爲(深奧的東西還很多,這裏只能是簡要地初步地膚淺地,隨着學習的深刻會一點點深刻地):
self.write()
向客戶端返回數據greeting = self.get_argument('greeting', 'Hello')
,因而不須要在get()中另外寫參數,只須要經過"greeting"就能夠獲得URL中的數據,不過這時候的url應該寫成http://localhost:8000/?greeting=PYTHON
的樣式,因而字符傳'PYTHON'就可以讓get()中的self.get_argument('greeting','Hello')
得到,若是沒有,就是'Hello'。sel.argument("text")
的形式獲得text
爲標籤提交的數據。get和post是http中用的最多的方法啦。此外,Tornado也還支持其它的HTTP請求,如:PUT、DELETE、HEAD、OPTIONS。在具體編程的時候,若是看官用到,能夠搜索,通常用的很少。
最後交代一句,get和post方法,因爲一個是經過URL獲得數據,另一個不是,因此,他們能夠寫到同一個類中,彼此互不干擾。
還要說明,我在這部分參考了一本書的講授內容,特別是其中的代碼例子,這本書就是《Introduction to Tornado》