美文网首页
tornado源码解读 - application、handle

tornado源码解读 - application、handle

作者: 羊驼xia | 来源:发表于2019-08-26 23:36 被阅读0次

调了好久的tornado接口,一直不知道收到请求后怎么就到了handler的get/post中处理请求,想看看源码长啥样。

下面是官方文档中的例程:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

上面的例程首先定义了一个handler,然后将handler与url的对应关系送入application,生成一个application实例,最后在app.listen中将app实例送入httpserver,并开启ioloop。


Application

tornado.web.Application负责为请求指路。
在初始化时,application会接受一个从url到handler的路由表,application在收到请求后会根据路由表,启动相应的handler处理请求。

当请求到来时,httpserver会调用Application.__call__()函数(还没看server,仅是猜测),这个函数接受一个请求,并根据请求找到相应的handler,最终调用这个handler的_execute函数。(下文再讲handler)

class Application(ReversibleRouter):
    ...
    def __call__(self, request):
        # Legacy HTTPServer interface
        dispatcher = self.find_handler(request)
        return dispatcher.execute()

上文中的self.find_handler(request)层层调用和继承, 路径大概是下面这样,最终其实返回了一个名为handlerdelegate的类的实例。

Application.find_handler()
-->
_ApplicationRouter.find_handler(request)(继承至RuleRouter)
-->
_ApplicationRouter.get_target_delegate()(重写了RuleRouter中的get_target_delegate)
-->
Application.get_handler_delegate()
-->
_HandlerDelegate

相关源码:

class Application(ReversibleRouter):
    def __init__(self,handlers=None,...)
        ...
        self.default_router = _ApplicationRouter(...)
        ...

    def find_handler(self, request, **kwargs):
        route = self.default_router.find_handler(request)
        if route is not None:
            return route

    def get_handler_delegate(self, ...):
        return _HandlerDelegate(...)


class _ApplicationRouter(ReversibleRuleRouter):
    ...
    def get_target_delegate(self, ...):
        if isclass(target) and issubclass(target, RequestHandler):
            return self.application.get_handler_delegate(request, target, **target_params)

        return super(_ApplicationRouter, self).get_target_delegate(target, request, **target_params)

class ReversibleRuleRouter(ReversibleRouter, RuleRouter):
    ...
    
class RuleRouter(Router):
    ...
    
    def find_handler(self, request, **kwargs):
        ...
        delegate = self.get_target_delegate()

        if delegate is not None:
            return delegate


Application.find_handler() 中的dispatcher就是_HandlerDelegate的一个实例
dispatcher.execute() 最终会调用RequestHandler._execute().
这个函数才是收到请求后真正执行的函数。(下面的handler部分再详细说)
执行完之后会返回一个future对象。

_HandlerDelegate.execute()
-->
RequestHandler._execute()

相关源码

class _HandlerDelegate(httputil.HTTPMessageDelegate):
    def execute(self):
        ...
        if self.stream_request_body:
            self.handler._prepared_future = Future()

        self.handler._execute(transforms, *self.path_args,
                              **self.path_kwargs)

        return self.handler._prepared_future

每次响应请求时,RequestHandler都会调用Application中的log_request 函数,就是这里才会使每次请求都记入日志。

access_log = logging.getLogger("tornado.access")

class Application(ReversibleRouter):
    ...
    def log_request(self, handler):
        """Writes a completed HTTP request to the logs.

        By default writes to the python root logger.  To change
        this behavior either subclass Application and override this method,
        or pass a function in the application settings dictionary as
        ``log_function``.
        """
        if "log_function" in self.settings:
            self.settings["log_function"](handler)
            return
        if handler.get_status() < 400:
            log_method = access_log.info
        elif handler.get_status() < 500:
            log_method = access_log.warning
        else:
            log_method = access_log.error
        request_time = 1000.0 * handler.request.request_time()
        log_method("%d %s %.2fms", handler.get_status(),
                   handler._request_summary(), request_time)


RequestHandler

所有处理请求的类都继承自RequestHandler

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

实际使用中需要自定义一个RequestHandler的子类。
如果自定义初始化,不能直接重写__init__(),
取而代之的是重写initialize()
在RequestHandler的__init__中最终会调用initialize().

class RequestHandler(object):
    def __init__(self, application, request, **kwargs):
        ...
        self.initialize(**kwargs)
    
    def initialize(self):
        pass

RequestHandler中写好了常用请求类型的接口,比如get,post,
需要在子类中重写对应类别的函数。

class RequestHandler(object):
    ...
    def get(self, *args, **kwargs):
        raise HTTPError(405)

    def post(self, *args, **kwargs):
        raise HTTPError(405)

    def delete(self, *args, **kwargs):...
    def patch(self, *args, **kwargs):...
    def put(self, *args, **kwargs):...
    def options(self, *args, **kwargs):...

上面提到,服务每次收到请求都会调用RequestHandler._execute()
这个函数会先调用prepare(),如果需要在所有请求处理的开头都执行相同的步骤,可以重写这个方法。

_execute() 会调用我们重写的get/post之类的函数,将其命名为method

如果在子类中没有显式调用self.finish(),程序将自动调用。

class RequestHandler(object):
    ...
    
    def prepare(self):
        pass

    @gen.coroutine
    def _execute(self, transforms, *args, **kwargs):
        ...
        result = self.prepare()
        ...
        method = getattr(self, self.request.method.lower())
        result = method(*self.path_args, **self.path_kwargs)
        ...
        if self._auto_finish and not self._finished:
            self.finish()


finish 这个方法会将数据写入缓存并发送回客户端,
finish 最后调用on_finish(),如果所有的子类都有共同的结束流程,可以重写这个函数,意思跟prepare()一样。
RequestHandler.finish() 不是一定要在handler结束时调用,可以提前调用,减少响应时间,调用之后可以在本地做其他事情

这个函数还会调用_log() 方法写入日志,_log() 函数实际调用的是Application中的log_request()

RequestHandler.finish()长这样

class RequestHandler(object):
    ...
    def on_finish(self):
        pass
    
    def finish(self, chunk=None):
        """Finishes this response, ending the HTTP request."""
        if self._finished:
            raise RuntimeError("finish() called twice")

        if chunk is not None:
            self.write(chunk)
        ...
        self.flush(include_footers=True)
        self.request.finish()
        self._log()
        self._finished = True
        self.on_finish()
        self._break_cycles()

有不对的地方请大家指正

相关文章

网友评论

      本文标题:tornado源码解读 - application、handle

      本文链接:https://www.haomeiwen.com/subject/jxbjectx.html