內容原子官方文檔:
Tornado基礎
Tornado是一套web框架和異步網絡功能庫,使用非阻塞式IO,可支持數萬個活動連接。支持長活躍連接,支持 long polling長連接,支持WebSockets。
A web framework (including RequestHandler which is subclassed to create web applications, and various supporting classes).
Client- and server-side implementions of HTTP (HTTPServer and AsyncHTTPClient).
An asynchronous networking library (IOLoop and IOStream), which serve as the building blocks for the HTTP components and can also be used to implement other protocols.
A coroutine library (tornado.gen) which allows asynchronous code to be written in a more straightforward way than chaining callbacks.
●一個web框架,包含RequestHandler 用於創建web應用程序。
●客戶端和服務端HTTP實現(HTTPServer and AsyncHTTPClient)。
●異步網絡庫(IOLoop and IOStream),可以用來建立HTTP組件,還可以實現其他協議。
●一個協程庫 (tornado.gen),可允許比鏈式回調地更加直接地編寫使用異步代碼。
Tornado可以作爲WSGI容器,也可以被包含在其他WSGI容器。
的幾種異步接口:
Callback argument
Return a placeholder (Future, Promise, Deferred)
Deliver to a queue
Callback registry (e.g. POSIX signals)
●回調參數
●返回一個佔位類 (Future, Promise, Deferred)
●遞交到隊列
●回調註冊(例如POSIX信號)
同步方式的代碼示例:
from tornado.httpclient import HTTPClientdef synchronous_fetch(url): http_client = HTTPClient() response = http_client.fetch(url) return response.body
回調方式的示例代碼:
from tornado.httpclient import AsyncHTTPClientdef asynchronous_fetch(url, callback): http_client = AsyncHTTPClient() def handle_response(response): callback(response.body) http_client.fetch(url, callback=handle_response)
使用Future的示例代碼:
from tornado.concurrent import Futuredef async_fetch_future(url): http_client = AsyncHTTPClient() my_future = Future() fetch_future = http_client.fetch(url) fetch_future.add_done_callback( lambda f: my_future.set_result(f.result())) return my_future
使用gen和協程方式的實例代碼:
from tornado import gen @gen.coroutine def fetch_coroutine(url): http_client = AsyncHTTPClient() response = yield http_client.fetch(url) raise gen.Return(response.body)
Coroutines 協程
另一個gen和協程的實現代碼:
from tornado import [email protected] fetch_coroutine(url): http_client = AsyncHTTPClient() response = yield http_client.fetch(url) return response.body
包含yield的函數是一個generator,它是異步的,返回generator對象無需等到運行完成。
def run(self): # send(x) makes the current yield return x. # It returns when the next yield is reached future = self.gen.send(self.next) def callback(f): self.next = f.result() self.run() future.add_done_callback(callback)
協程調用模式
和回調交互:將調用包裹在Task中,可以返回一個Future對象,並加入回調的參數。
@gen.coroutinedef call_task(): # Note that there are no parens on some_function. # This will be translated by Task into # some_function(other_args, callback=callback) yield gen.Task(some_function, other_args)
調用阻塞函數:使用ThreadPoolExecutor,可以返回和協程兼容的Future。
thread_pool = ThreadPoolExecutor(4) @gen.coroutine def call_blocking(): yield thread_pool.submit(blocking_func, args)
並行執行:協程裝飾器能識別類型爲Futures的列表和字典,並且等待所有這些Future並行執行完成
@gen.coroutine def parallel_fetch(url1, url2): resp1, resp2 = yield [http_client.fetch(url1), http_client.fetch(url2)]@gen.coroutinedef parallel_fetch_many(urls): responses = yield [http_client.fetch(url) for url in urls] # responses is a list of HTTPResponses in the same [email protected] parallel_fetch_dict(urls): responses = yield {url: http_client.fetch(url) for url in urls} # responses is a dict {url: HTTPResponse}
交替執行:有些時候需要保存Future而不是讓他立即執行,可以在等待時開始一個新的操作
@gen.coroutinedef get(self): fetch_future = self.fetch_next_chunk() while True: chunk = yield fetch_future if chunk is None: break self.write(chunk) fetch_future = self.fetch_next_chunk() yield self.flush()
循環:需要從訪問的結果拆解循環條件,類似在Motor中的用法
import motordb = motor.MotorClient().test @gen.coroutine def loop_example(collection): cursor = db.collection.find() while (yield cursor.fetch_next): doc = cursor.next_object()
基本程序結構
from tornado.ioloop import IOLoop from tornado.web import RequestHandler, Application, url class HelloHandler(RequestHandler): def get(self): self.write("Hello, world")def make_app(): return Application([ url(r"/", HelloHandler), ]) def main(): app = make_app() app.listen(8888) IOLoop.current().start()
Application和路由
class MainHandler(RequestHandler): def get(self): self.write('<a href="%s">link to story 1</a>' % self.reverse_url("story", "1"))class StoryHandler(RequestHandler): def initialize(self, db): self.db = db def get(self, story_id): self.write("this is story %s" % story_id) app = Application([ url(r"/", MainHandler), url(r"/story/([0-9]+)", StoryHandler, dict(db=db), name="story") ])
處理輸入請求
可以使用get_query_argument and get_body_argument方法,獲取get或表單的數據
class MyFormHandler(RequestHandler): def get(self): self.write('<html><body><form action="/myform" method="POST">' '<input type="text" name="message">' '<input type="submit" value="Submit">' '</form></body></html>') def post(self): self.set_header("Content-Type", "text/plain") self.write("You wrote " + self.get_body_argument("message"))
如果數據是json方式的
def prepare(self): if self.request.headers["Content-Type"].startswith("application/json"): self.json_args = json.loads(self.request.body) else: self.json_args = None
覆蓋RequestHandler 中的方法
write_error - 輸出HTML的錯誤頁面。
on_connection_close - 客戶端斷開連接時調用; 應用程序可以檢測這種情況 並終止後續的處理。 注意不能保證連接斷開的檢測是準確的。
get_current_user - 參看 User authentication (用戶授權)
get_user_locale - 返回 Locale 對象給當前的用戶
set_default_headers - 可以用於設置附加的html相應頭 (例如自定義Server 頭)
錯誤處理
RequestHandler.write_error 用來產生一個錯誤頁。
tornado.web.HTTPError用來產生錯誤狀態碼。
重定向
可以通過兩種方式實現重定向。
RequestHandler.redirect and with theRedirectHandler.
RedirectHandler用於配置重定向在路由中。
app = tornado.web.Application([ url(r"/app", tornado.web.RedirectHandler, dict(url="http://itunes.apple.com/my-app-id")), ])
支持正則表達式
app = tornado.web.Application([ url(r"/photos/(.*)", MyPhotoHandler), url(r"/pictures/(.*)", tornado.web.RedirectHandler, dict(url=r"/photos/\1")), ])
異步處理
異步處理通常可以使用兩種形式:
coroutine 裝飾器 + yield關鍵字
tornado.web.asynchronous裝飾器 + callback ,請求會一直保持打開,callback完成返回時調用RequestHandler.finish ,響應這時再發出
callback模式的示例,使用內置的AsyncHTTPClient:
class MainHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): http = tornado.httpclient.AsyncHTTPClient() http.fetch("http://friendfeed-api.com/v2/feed/bret", callback=self.on_response) def on_response(self, response): if response.error: raise tornado.web.HTTPError(500) json = tornado.escape.json_decode(response.body) self.write("Fetched " + str(len(json["entries"])) + " entries " "from the FriendFeed API") self.finish()
協程模式的示例:
class MainHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): http = tornado.httpclient.AsyncHTTPClient() response = yield http.fetch("http://friendfeed-api.com/v2/feed/bret") json = tornado.escape.json_decode(response.body) self.write("Fetched " + str(len(json["entries"])) + " entries " "from the FriendFeed API")