簡單的web services: html
如今咱們將開始瞭解什麼是tornado,tornado能夠作什麼。咱們來經過分析tornado實現的一個簡單web service 例子開始吧。 python
Hello Tornado 程序員
tornado 是一個能夠處理http請求的框架,你的工做是做爲一個程序員,編寫一個handlers來響應一個標準的http請求。,下面是這個例子的全部代碼: web
範例1:hello.py 正則表達式
- import tornado.httpserver
- import tornado.ioloop
- import tornado.options
- import tornado.web
- from tornado.options import define, options
- define(「port」, default=8000, help=」run on the given port」, type=int)
-
- class IndexHandler(tornado.web.RequestHandler):
- def get(self):
- greeting = self.get_argument(‘greeting’, ’Hello’)
- self.write(greeting + ’, friendly user!’)
-
- if __name__ == 」__main__「:
- tornado.options.parse_command_line()
- app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
- http_server = tornado.httpserver.HTTPServer(app)
- http_server.listen(options.port)
- tornado.ioloop.IOLoop.instance().start()
實際上咱們大部分的工做是使用tornado的接口去定義一個類來擴展tornado 的RequestHandler類,在這個例子中,咱們將會定義一個簡單的應用來監遵從端口得到的請求,而且返回一個響應值。 數據庫
你能夠經過命令行去試着運行和測試你本身的代碼: 瀏覽器
- $ python hello.py –port=8000
如今你能夠經過瀏覽器訪問http://localhost:8000/,或者在另一個獨立的命令行窗口使用curl命令測試這個應用: app
- $ curl http://localhost:8000/
- Hello, friendly user!
- $ curl http://localhost:8000/?greeting=Salutations
- Salutations, friendly user!
讓咱們回到這個例子下,一步一步對它進行分析吧! 框架
- import tornado.httpserver
- import tornado.ioloop
- import tornado.options
- import tornado.web
在程序的最上面,咱們導入各類tornado的函數庫,這裏還包括更多的tornado函數庫,可是在這個例子中你只須要導入四個函數庫就能夠運行了: curl
- from tornado.options import define, options
- define(「port」, default=8000, help=」run on the given port」, type=int)
tornado集成了一些有用的函數在tornado.options裏面,在這裏咱們使用這個函數庫來完成監聽HTTP請求的應用,這些參數將會對全部對象生效,若是你是在命令行中輸入–help,你將會看到全部的幫助信息及其定義。若是你沒有輸入一個值,那麼default變量後面的參數將會做爲默認值開始執行,假如你輸入的是一個錯誤的類型,程序將會拋出一個錯誤,在這裏容許使用一個整數型數據做爲監聽的端口,若是沒有輸入任何數據,程序將會使用默認端口8000。
- class IndexHandler(tornado.web.RequestHandler):
- def get(self):
- greeting = self.get_argument(‘greeting’, ’Hello’)
- self.write(greeting + ’, friendly user!’)
這是一個tornado處理請求的類,當出現請求時,tornado實例將會調用這個類和方法。在這個例子中,咱們只定義了一個get方法,這意味着程序只能處理HTTP GET的請求,在後面咱們將會學習到如何使用更多接口去響應HTTP不一樣的請求。
- greeting = self.get_argument(‘greeting’, ’Hello’)
tornado的請求類擁有不少有用的方法,好比get_argument,這個方法可讓咱們得到請求字符串中的變量(若是請求中不包含字符串,tornado將會使用第二種方法替代get_argument,並使用默認值)
Code ViewCopyPrint
- self.write(greeting + ‘, friendly user!’)
第二個方法是使用一個請求的方法,當請求中有字符串變量時,咱們將會獲取這個字符串,而且插入一個問候語響應這條請求。
- if __name__ == 」__main__「:
- tornado.options.parse_command_line()
- app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
tornado的應用將會從這裏開始執行,首先咱們經過tornado的options函數庫去解析命令,當咱們建立一個tornado應用類的實例的時候,全部導入的變量將會傳送到類的__init__方法中,這個方法將會告訴tornado須要調用哪個handle ,咱們將會在後面對此作詳細的說明。
- http_server = tornado.httpserver.HTTPServer(app)
- http_server.listen(options.port)
- 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
- 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=」run on the given port」, type=int)
- class ReverseHandler(tornado.web.RequestHandler):
- def get(self, input):
- self.write(input[::-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()
和第一個例子同樣,你能夠像這樣在命令行中運行它
- $ python string_service.py –port=8000
這個程序是一個用於處理字符串的基礎web框架,如今你能夠對它作兩件事情。
第一:經過GET向 /reverse/string請求返回一個特定的字符串,相似這樣的URL結構
- $ curl http://localhost:8000/reverse/stressed
- desserts
- $ curl http://localhost:8000/reverse/slipup
- pupils
第二:經過POST向/wrap提交請求,並將返回的字符串顯示出來。這個請求包括一個無長度限制的字符串,在程序中,咱們經過get_argument來接收這個字符串變量。你能夠這麼測試:
- $ curl http://localhost:8000/wrap »
- -d text=Lorem+ipsum+dolor+sit+amet,+consectetuer+adipiscing+elit.
- Lorem ipsum dolor sit amet, consectetuer
- adipiscing elit.
curl命令顯示的是兩行命令,可是咱們輸入的應該只是一行的命令,因此咱們使用雙引字符(>>)來表示命令行的延續
這個字符串服務的例子大部分代碼和上一個例子是相同的,讓咱們將注意力集中到那些新增的不一樣代碼中來,首先讓咱們來看看程序中傳送給handlers的變量有什麼不一樣:
- app = tornado.web.Application(handlers=[
- (r"/reverse/(\w+)", ReverseHandler),
- (r"/wrap", WrapHandler)
- ])
在這個例子的代碼中,咱們能夠看到有兩個RequestHandlers實例化的類對Handlers進行處理,第一個tornado請求的地址按照下面的正則表達式進行匹配:
這個正則表達式告訴tornado,他將會匹配一個/reverse/後面跟着一個或多個數字、字母的字符串,括號的含義是告訴tornado,須要將括號中匹配的字符串做爲RequestHandler的請求參數,咱們能夠查看ReverseHandler的定義去了解它是如何工做的:
- class ReverseHandler(tornado.web.RequestHandler):
- def get(self, input):
- self.write(input[::-1])
你能夠看到這個類中,get方法須要輸入一個額外的參數,這個參數是在第一個正則表達式中,徹底匹配括號內的表達式的一個字符串,(假若有多個括號分割的正則表達式,能夠按照相同的順序在get中添加接收的參數的變量)
如今,讓咱們來看看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))
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的值。
- # matched with (r」/widget/(\d+)」, WidgetHandler)
- class WidgetHandler(tornado.web.RequestHandler):
- def get(self, widget_id):
- widget = retrieve_from_db(widget_id)
- self.write(widget.serialize())
- def post(self, widget_id):
- widget = retrieve_from_db(widget_id)
- widget['foo'] = self.get_argument(‘foo’)
- save_to_db(widget)
截止目前咱們討論的例子中只使用了GET 和 POST的方法,實際上tornado還支持更多的HTTP方法(GET,POST,PUT,DELETE,HEAD,OPTIONS),在你編寫的RequestHandler類中能夠經過定義不一樣的方法去使用他們。在下面的虛擬案例中,咱們將會使用HEAD方法去判斷請求中的frob是否存在於數據庫中,當存在時咱們經過GET方法將frob對應的數據庫信息返回給請求的客戶端:
- # matched with (r」/frob/(\d+)」, FrobHandler)
- class FrobHandler(tornado.web.RequestHandler):
- def head(self, frob_id):
- frob = retrieve_from_db(frob_id)
- if frob is not None:
- self.set_status(200)
- else:
- self.set_status(404)
- def get(self, frob_id):
- frob = retrieve_from_db(frob_id)
- 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,讓你瞭解如何將初始化的錯誤信息從新改寫。
- import tornado.httpserver
- import tornado.ioloop
- import tornado.options
- import tornado.web
- from tornado.options import define, options
- define(「port」, default=8000, help=」run on the given port」, type=int)
- class IndexHandler(tornado.web.RequestHandler):
- def get(self):
- greeting = self.get_argument(‘greeting’, ’Hello’)
- self.write(greeting + ’, friendly user!’)
- def write_error(self, status_code, **kwargs):
- self.write(「Gosh darnit, user! You caused a %d error.」 % status_code)
- if __name__ == 」__main__「:
- tornado.options.parse_command_line()
- app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
- http_server = tornado.httpserver.HTTPServer(app)
- http_server.listen(options.port)
- tornado.ioloop.IOLoop.instance().start()
在當咱們使用POST向handler發送請求時,將會出現下面的響應,由於咱們已經把tornado默認的錯誤響應重寫了:
- $ curl -d foo=bar http://localhost:8000/
- 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