内容原子官方文档:


  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 (FuturePromiseDeferred)

  • Deliver to a queue

  • Callback registry (e.g. POSIX signals)

●回调参数

●返回一个占位类 (FuturePromiseDeferred)

●递交到队列

●回调注册(例如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 gen@gen.coroutinedef 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 order@gen.coroutinedef 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的错误页面。

错误处理


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")