翻譯:introduce to tornado - a simple example

簡單的web services: html

如今咱們將開始瞭解什麼是tornado,tornado能夠作什麼。咱們來經過分析tornado實現的一個簡單web service 例子開始吧。python

Hello Tornado 程序員

tornado 是一個能夠處理http請求的框架,你的工做是做爲一個程序員,編寫一個handlers來響應一個標準的http請求。,下面是這個例子的全部代碼:web

範例1:hello.py正則表達式

Code      View   Copy   Print  數據庫

  1. import tornado.httpserver   瀏覽器

  2. import tornado.ioloop   app

  3. import tornado.options   框架

  4. import tornado.web   curl

  5. from tornado.options import define, options   

  6. define(「port」, default=8000, help=」run on the given port」, type=int)   

  7.   

  8. class IndexHandler(tornado.web.RequestHandler):   

  9.     def get(self):   

  10.         greeting = self.get_argument(‘greeting’, ’Hello’)   

  11.         self.write(greeting + ’, friendly user!’)   

  12.   

  13. if __name__ == 」__main__「:   

  14.     tornado.options.parse_command_line()   

  15.     app = tornado.web.Application(handlers=[(r"/", IndexHandler)])   

  16.     http_server = tornado.httpserver.HTTPServer(app)   

  17.     http_server.listen(options.port)   

  18.     tornado.ioloop.IOLoop.instance().start()  

實際上咱們大部分的工做是使用tornado的接口去定義一個類來擴展tornado 的RequestHandler類,在這個例子中,咱們將會定義一個簡單的應用來監遵從端口得到的請求,而且返回一個響應值。

你能夠經過命令行去試着運行和測試你本身的代碼:

  1. $ python hello.py –port=8000  

如今你能夠經過瀏覽器訪問http://localhost:8000/,或者在另一個獨立的命令行窗口使用curl命令測試這個應用:

  1. $ curl http://localhost:8000/   

  2. Hello, friendly user!   

  3. $ curl http://localhost:8000/?greeting=Salutations   

  4. Salutations, friendly user!  

讓咱們回到這個例子下,一步一步對它進行分析吧!

Code      View   Copy   Print  

  1. import tornado.httpserver   

  2. import tornado.ioloop   

  3. import tornado.options   

  4. import tornado.web  

在程序的最上面,咱們導入各類tornado的函數庫,這裏還包括更多的tornado函數庫,可是在這個例子中你只須要導入四個函數庫就能夠運行了:

Code      View   Copy   Print  

  1. from tornado.options import define, options   

  2. define(「port」, default=8000, help=」run on the given port」, type=int)  

tornado集成了一些有用的函數在tornado.options裏面,在這裏咱們使用這個函數庫來完成監聽HTTP請求的應用,這些參數將會對全部 對象生效,若是你是在命令行中輸入–help,你將會看到全部的幫助信息及其定義。若是你沒有輸入一個值,那麼default變量後面的參數將會做爲默認 值開始執行,假如你輸入的是一個錯誤的類型,程序將會拋出一個錯誤,在這裏容許使用一個整數型數據做爲監聽的端口,若是沒有輸入任何數據,程序將會使用默 認端口8000。

Code      View   Copy   Print  

  1. class IndexHandler(tornado.web.RequestHandler):   

  2.     def get(self):   

  3.         greeting = self.get_argument(‘greeting’, ’Hello’)   

  4.         self.write(greeting + ’, friendly user!’)  

這是一個tornado處理請求的類,當出現請求時,tornado實例將會調用這個類和方法。在這個例子中,咱們只定義了一個get方法,這意味着程序只能處理HTTP GET的請求,在後面咱們將會學習到如何使用更多接口去響應HTTP不一樣的請求。

 

Code      View   Copy   Print  

  1. greeting = self.get_argument(‘greeting’, ’Hello’)  

tornado的請求類擁有不少有用的方法,好比get_argument,這個方法可讓咱們得到請求字符串中的變量(若是請求中不包含字符串,tornado將會使用第二種方法替代get_argument,並使用默認值)

Code   ViewCopyPrint

  1. self.write(greeting + ‘, friendly user!’)

第二個方法是使用一個請求的方法,當請求中有字符串變量時,咱們將會獲取這個字符串,而且插入一個問候語響應這條請求。

 

Code      View   Copy   Print  

  1. if __name__ == 」__main__「:   

  2.     tornado.options.parse_command_line()   

  3.     app = tornado.web.Application(handlers=[(r"/", IndexHandler)])  

tornado的應用將會從這裏開始執行,首先咱們經過tornado的options函數庫去解析命令,當咱們建立一個tornado應用類的實例的時 候,全部導入的變量將會傳送到類的__init__方法中,這個方法將會告訴tornado須要調用哪個handle ,咱們將會在後面對此作詳細的說明。

 

  1. http_server = tornado.httpserver.HTTPServer(app)   

  2. http_server.listen(options.port)   

  3. tornado.ioloop.IOLoop.instance().start()  

程序將從這裏開始執行,建立一個實例,咱們經過應用tornado的HTTPServer對象來監聽指定的端口在命令行中獲取的數據,而後咱們建立一個tornado的IOLoop實例,最後這個程序將會開始接收HTTP請求。

操做的變量

讓咱們再回頭看看helly.py這個例子的第一行:

app = tornado.web.Application(handlers=[(r"/", IndexHandler)])

這個handlers很是重要,咱們將會在後面對它進行更詳細的解釋,它是一個元組的列表,咱們使用一個正則表達式將它與RequestHandler進行匹配,你能夠添加更多的列表來指定更多須要匹配的RequestHandler。

 

使用正則表達式來指定URL

tornado使用正則表達式來匹配URL的http請求(RequestHandler的類在URL後面,不包括主機名和查詢字符串的片斷),它們應該 包含起始行和結束行。當一個正則表達式匹配一個HTTP請求時,匹配的內容將會做爲參數傳遞給RequestHandler的類。咱們將會在下一個例子了 解到它是如何工做的。

 

字符串服務

咱們將經過一個稍微複雜一些的例子1-2去介紹更多關於tornado的設計理念.

例1-2 Handling input: string_service.py

Code      View   Copy   Print  

  1. import textwrap  

  2. import tornado.httpserver   

  3. import tornado.ioloop   

  4. import tornado.options   

  5. import tornado.web   

  6. from tornado.options import define, options   

  7. define(「port」, default=8000, help=」run on the given port」, type=int)   

  8. class ReverseHandler(tornado.web.RequestHandler):   

  9.     def get(selfinput):   

  10.         self.write(input[::-1])   

  11.   

  12. class WrapHandler(tornado.web.RequestHandler):   

  13.     def post(self):   

  14.         text = self.get_argument(‘text’)   

  15.         width = self.get_argument(‘width’, 40)   

  16.         self.write(textwrap.fill(text, width))   

  17.   

  18. if __name__ == 」__main__「:   

  19.     tornado.options.parse_command_line()   

  20.     app = tornado.web.Application(   

  21.         handlers=[   

  22.             (r"/reverse/(\w+)", ReverseHandler),   

  23.             (r"/wrap", WrapHandler)   

  24.         ]   

  25.     )   

  26.     http_server = tornado.httpserver.HTTPServer(app)   

  27.     http_server.listen(options.port)   

  28.     tornado.ioloop.IOLoop.instance().start()  

和第一個例子同樣,你能夠像這樣在命令行中運行它

  1. $ python string_service.py –port=8000  

這個程序是一個用於處理字符串的基礎web框架,如今你能夠對它作兩件事情。

第一:經過GET向 /reverse/string請求返回一個特定的字符串,相似這樣的URL結構

Code      View   Copy   Print  

  1. $ curl http://localhost:8000/reverse/stressed   

  2. desserts   

  3. $ curl http://localhost:8000/reverse/slipup   

  4. pupils  

第二:經過POST向/wrap提交請求,並將返回的字符串顯示出來。這個請求包括一個無長度限制的字符串,在程序中,咱們經過get_argument來接收這個字符串變量。你能夠這麼測試:

  1. $ curl http://localhost:8000/wrap »   

  2. -d text=Lorem+ipsum+dolor+sit+amet,+consectetuer+adipiscing+elit.   

  3. Lorem ipsum dolor sit amet, consectetuer   

  4. adipiscing elit.  

 curl命令顯示的是兩行命令,可是咱們輸入的應該只是一行的命令,因此咱們使用雙引字符(>>)來表示命令行的延續

這個字符串服務的例子大部分代碼和上一個例子是相同的,讓咱們將注意力集中到那些新增的不一樣代碼中來,首先讓咱們來看看程序中傳送給handlers的變量有什麼不一樣:

Code      View   Copy   Print  

  1. app = tornado.web.Application(handlers=[   

  2.     (r"/reverse/(\w+)", ReverseHandler),   

  3.     (r"/wrap", WrapHandler)   

  4. ])  

在這個例子的代碼中,咱們能夠看到有兩個RequestHandlers實例化的類對Handlers進行處理,第一個tornado請求的地址按照下面的正則表達式進行匹配:

Code      View   Copy   Print  

  1. /reverse/(\w+)  

這個正則表達式告訴tornado,他將會匹配一個/reverse/後面跟着一個或多個數字、字母的字符串,括號的含義是告訴tornado,須要將括 號中匹配的字符串做爲RequestHandler的請求參數,咱們能夠查看ReverseHandler的定義去了解它是如何工做的:

Code      View   Copy   Print  

  1. class ReverseHandler(tornado.web.RequestHandler):   

  2.     def get(selfinput):   

  3.         self.write(input[::-1])  

你能夠看到這個類中,get方法須要輸入一個額外的參數,這個參數是在第一個正則表達式中,徹底匹配括號內的表達式的一個字符串,(假若有多個括號分割的正則表達式,能夠按照相同的順序在get中添加接收的參數的變量)

如今,讓咱們來看看WrapHandler的定義:

Code      View   Copy   Print  

  1. class WrapHandler(tornado.web.RequestHandler):   

  2.     def post(self):   

  3.         text = self.get_argument(‘text’)   

  4.         width = self.get_argument(‘width’, 40)   

  5.         self.write(textwrap.fill(text, width))  

WrapHandler的類會處理從請求中傳過來的字符串。咱們能夠看到這個類只定義了一個post的方法,這意味着它只能接收HTTP post的方法。咱們以前是用過這個RequestHandler對象來抓取從請求中傳過來的字符串做爲變量。如今咱們可使用一樣的方法去抓取POST 請求傳過來的變量(tornado能夠解析POST傳過來的URL字符串或參數),一旦咱們抓取到了字符串及其長度的參數,就可使用python內置的 textwrap函數庫庫去轉換字符串,而且經過HTTP返回生成的字符串做爲響應數據。

 

更多RequestHandlers

到目前爲止,咱們基於RequestHandler開發這些對象:如何經過HTTP獲取參數(使用get_argument 獲取GET和POST傳遞過來的參數)和如何編寫HTTP相應信息(使用write方法)。在咱們開始後面的章節學習以前,再給你介紹一些應用 RequestHandler須要注意的地方,以及tornado如何去使用它。

http方法:

截止目前討論的都是關於RequestHandler定義單個HTTP方法的問題,其實在一個類中,能夠定義或使用多個 handler,綁定多個功能到一個類中是一種很好的管理方式,你可能會編寫一個處理程序去獲取參數,而且經過POST和GET對象改變數據庫中一個特定 ID的值,例如:用一個GET方法中將抓取請求的ID和參數,而且使用POST方法修改數據庫中對應ID的值。

Code      View   Copy   Print  

  1. # matched with (r」/widget/(\d+)」, WidgetHandler)   

  2. class WidgetHandler(tornado.web.RequestHandler):   

  3.     def get(self, widget_id):   

  4.         widget = retrieve_from_db(widget_id)   

  5.         self.write(widget.serialize())   

  6.     def post(self, widget_id):   

  7.         widget = retrieve_from_db(widget_id)   

  8.         widget['foo'] = self.get_argument(‘foo’)   

  9.         save_to_db(widget)  

截止目前咱們討論的例子中只使用了GET 和 POST的方法,實際上tornado還支持更多的HTTP方法(GET,POST,PUT,DELETE,HEAD,OPTIONS),在你編寫的 RequestHandler類中能夠經過定義不一樣的方法去使用他們。在下面的虛擬案例中,咱們將會使用HEAD方法去判斷請求中的frob是否存在於數 據庫中,當存在時咱們經過GET方法將frob對應的數據庫信息返回給請求的客戶端:

Code      View   Copy   Print  

  1. # matched with (r」/frob/(\d+)」, FrobHandler)   

  2. class FrobHandler(tornado.web.RequestHandler):   

  3.     def head(self, frob_id):   

  4.         frob = retrieve_from_db(frob_id)   

  5.         if frob is not None:   

  6.             self.set_status(200)   

  7.         else:   

  8.             self.set_status(404)   

  9.     def get(self, frob_id):   

  10.         frob = retrieve_from_db(frob_id)   

  11.         self.write(frob.serialize())  

HTTP狀態碼:

在上一個展現的例子中,你能夠在你的RequestHandler使用set_status()設置HTTP狀態碼到客戶端的相應信息中,下面是一些比較重要的狀態碼。tornado也能夠根據你的相應自動去返回對應的狀態碼,在這裏咱們只列出比較經常使用的幾個狀態碼:

404 Not Found

若是HTTP請求的路徑不存在,tornado將會經過RequestHandler類自動將404(Not Found)返回給客戶端

400 Bad Request

若是使用get_argument沒有獲取到默認的參數哦,或者沒有找到定義的參數名,tornado將會自動將400(Bad Request)返回給客戶端。

405 Method Not Allowed

若是經過HTTP傳進來的請求沒有找到RequestHandler類中對應的方法(例如使用POST請求,可是handler方法對應的類倒是GET方法)tornado將會返回一個405(Method Not Allowed)給客戶端。

500 Internal Server Error

當遇到任何應用服務異常退出的錯誤時,tornado將會返回500( Internal Server Error)給客戶端,代碼中任何意外退出均可能致使tornado返回一個500錯誤代碼。

200 OK

若是請求成功完成了,而且沒有設置其它相應代碼,tornado默認將會自動返回一個200(OK)的響應給客戶端。

當出現一個錯誤出現時,tornado默認將會發送一個包含錯誤代碼和錯誤信息的html頁面給客戶端,若是你想要替換默認響應的錯誤信息成自定義的頁 面,你能夠在你的RequestHandler中重寫write_error方法,例子1-3將會向你展現咱們修改的hello.py,讓你瞭解如何將初 始化的錯誤信息從新改寫。

Code      View   Copy   Print  

  1. import tornado.httpserver   

  2. import tornado.ioloop   

  3. import tornado.options   

  4. import tornado.web   

  5. from tornado.options import define, options   

  6. define(「port」, default=8000, help=」run on the given port」, type=int)   

  7. class IndexHandler(tornado.web.RequestHandler):   

  8.     def get(self):   

  9.         greeting = self.get_argument(‘greeting’, ’Hello’)   

  10.         self.write(greeting + ’, friendly user!’)   

  11.     def write_error(self, status_code, **kwargs):   

  12.         self.write(「Gosh darnit, user! You caused a %d error.」 % status_code)   

  13. if __name__ == 」__main__「:   

  14.     tornado.options.parse_command_line()   

  15.     app = tornado.web.Application(handlers=[(r"/", IndexHandler)])   

  16.     http_server = tornado.httpserver.HTTPServer(app)   

  17.     http_server.listen(options.port)   

  18.     tornado.ioloop.IOLoop.instance().start()  

在當咱們使用POST向handler發送請求時,將會出現下面的響應,由於咱們已經把tornado默認的錯誤響應重寫了:

Code      View   Copy   Print  

  1. $ curl -d foo=bar http://localhost:8000/   

  2. Gosh darnit, user! You caused a 405 error.  

下一步

如今你對tornado已經有了基本的理解,咱們但願你能有迫切學習更多知識的動力。在後續的章節,咱們將向你展現更多的功能和技術,幫助你使用tornado去創建一個完整的web server和web應用。

原創翻譯,首發地址:http://blog.xihuan.de/tech/web/tornado/

上一篇:翻譯:introduce to tornado - introduce

下一篇:翻譯:introduce to tornado - form and template

相關文章
相關標籤/搜索