翻譯: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   
  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.   
  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命令測試這個應用: app

  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函數庫,可是在這個例子中你只須要導入四個函數庫就能夠運行了: curl

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

相關文章
相關標籤/搜索