美文网首页生活不易 我用python
tornado3第二部分分析tornado处理路由__call_

tornado3第二部分分析tornado处理路由__call_

作者: lpj24 | 来源:发表于2015-01-16 10:14 被阅读706次

    (代码缩进有点问题  大家可以看源码)

    tornado有许多关于如何处理路由列表的源码分析的博客,关键在与调用了Application.__call__函数,然后遍历路由列表,取出对应的处理类,由于处理类都是RequestHandler类,调用的是父类的_excute()进行响应处理,我们要了解的是__call__函数和什么时候调用了__call__函数

    def __call__(self, request):

    """Called by HTTPServer to execute the request."""

    transforms = [t(request) for t in self.transforms]

    handler = None

    args = []

    kwargs = {}

    handlers = self._get_host_handlers(request)

    if not handlers:

    handler = RedirectHandler(

    self, request, url="http://" + self.default_host + "/")

    else:

    for spec in handlers:

    match = spec.regex.match(request.path)

    if match:

    handler = spec.handler_class(self, request, **spec.kwargs)

    if spec.regex.groups:

    # None-safe wrapper around url_unescape to handle

    # unmatched optional groups correctly

    def unquote(s):

    if s is None:

    return s

    return escape.url_unescape(s, encoding=None,

    plus=False)

    # Pass matched groups to the handler.  Since

    # match.groups() includes both named and unnamed groups,

    # we want to use either groups or groupdict but not both.

    # Note that args are passed as bytes so the handler can

    # decide what encoding to use.

    if spec.regex.groupindex:

    kwargs = dict(

    (str(k), unquote(v))

    for (k, v) in match.groupdict().items())

    else:

    args = [unquote(s) for s in match.groups()]

    break

    if not handler:

    if self.settings.get('default_handler_class'):

    handler_class = self.settings['default_handler_class']

    handler_args = self.settings.get(

    'default_handler_args', {})

    else:

    handler_class = ErrorHandler

    handler_args = dict(status_code=404)

    handler = handler_class(self, request, **handler_args)

    # If template cache is disabled (usually in the debug mode),

    # re-compile templates and reload static files on every

    # request so you don't need to restart to see changes

    if not self.settings.get("compiled_template_cache", True):

    with RequestHandler._template_loader_lock:

    for loader in RequestHandler._template_loaders.values():

    loader.reset()

    if not self.settings.get('static_hash_cache', True):

    StaticFileHandler.reset()

    handler._execute(transforms, *args, **kwargs)

    return handler

    当http_server.listen(options.port)启动监听的时候,程序会accept socket.详见netutil.add_accept_handler函数,我们要注意传递的第一个参数_handle_connection是什么,是一个函数,这里先不具体看函数,我们看看到add_accept_handler后是怎么处理这些参数的

    def listen(self, port, address=""):

    if self.io_loop is None:

    self.io_loop = IOLoop.current()

    for sock in sockets:

    self._sockets[sock.fileno()] = sock

    add_accept_handler(sock, self._handle_connection,

    io_loop=self.io_loop)

    def _handle_connection(self, connection, address):

    if self.ssl_options is not None:

    assert ssl, "Python 2.6+ and OpenSSL required for SSL"

    try:

    connection = ssl_wrap_socket(connection,

    self.ssl_options,

    server_side=True,

    do_handshake_on_connect=False)

    except ssl.SSLError as err:

    if err.args[0] == ssl.SSL_ERROR_EOF:

    return connection.close()

    else:

    raise

    except socket.error as err:

    if err.args[0] in (errno.ECONNABORTED, errno.EINVAL):

    return connection.close()

    else:

    raise

    try:

    if self.ssl_options is not None:

    stream = SSLIOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size)

    else:

    stream = IOStream(connection, io_loop=self.io_loop, max_buffer_size=self.max_buffer_size)

    self.handle_stream(stream, address)

    except Exception:

    app_log.error("Error in connection callback", exc_info=True)

    #这是add_accept_handler(sock, self._handle_connection,io_loop=self.io_loop)

    def add_accept_handler(sock, callback, io_loop=None):

    """Adds an `.IOLoop` event handler to accept new connections on ``sock``.

    When a connection is accepted, ``callback(connection, address)`` will

    be run (``connection`` is a socket object, and ``address`` is the

    address of the other end of the connection).  Note that this signature

    is different from the ``callback(fd, events)`` signature used for

    `.IOLoop` handlers.

    """

    if io_loop is None:

    io_loop = IOLoop.current()

    def accept_handler(fd, events):

    while True:

    try:

    connection, address = sock.accept()

    except socket.error as e:

    # EWOULDBLOCK and EAGAIN indicate we have accepted every

    # connection that is available.

    if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):

    return

    # ECONNABORTED indicates that there was a connection

    # but it was closed while still in the accept queue.

    # (observed on FreeBSD).

    if e.args[0] == errno.ECONNABORTED:

    continue

    raise

    callback(connection, address)

    io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ)

    add_accept_handler(sock, callback, io_loop=None)函数接受request请求,调用了callback(connection,address)函数并且给IO事件循环注册了一个事件,我们应该知道callback()函数的,就是传递过来的参数_handle_connection()再看看这个函数做了什么处理分析不管前面做了什么处理,有一句是要执行的self.handle_stream(stream, address),原来调用了HttpServer的

    def handle_stream(self, stream, address):

    HTTPConnection(stream, address, self.request_callback,

    self.no_keep_alive, self.xheaders, self.protocol)

    调用了HTTPConnection对象,很简单,应该只调用了构造方法

    看看Httpserver的构造方法

    def __init__(self, request_callback, no_keep_alive=False, io_loop=None,

    xheaders=False, ssl_options=None, protocol=None, **kwargs):

    self.request_callback = request_callback

    self.no_keep_alive = no_keep_alive

    self.xheaders = xheaders

    self.protocol = protocol

    TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,

    **kwargs)

    def handle_stream(self, stream, address):

    HTTPConnection(stream, address, self.request_callback,

    self.no_keep_alive, self.xheaders, self.protocol)

    request_callback是什么http_server = tornado.httpserver.HTTPServer(Application())这里清楚了是Application(),分析

    def __init__(self, stream, address, request_callback, no_keep_alive=False,

    xheaders=False, protocol=None):

    self.stream = stream

    self.address = address

    # Save the socket's address family now so we know how to

    # interpret self.address even after the stream is closed

    # and its socket attribute replaced with None.

    self.address_family = stream.socket.family

    self.request_callback = request_callback

    self.no_keep_alive = no_keep_alive

    self.xheaders = xheaders

    self.protocol = protocol

    self._clear_request_state()

    # Save stack context here, outside of any request.  This keeps

    # contexts from one request from leaking into the next.

    self._header_callback = stack_context.wrap(self._on_headers)

    self.stream.set_close_callback(self._on_connection_close)

    self.stream.read_until(b"\r\n\r\n", self._header_callback)

    self._header_callback = stack_context.wrap(self._on_headers)这一句很关键,

    def _on_headers(self, data):

    #省略******

    self.request_callback(self._request)

    return

    self.request_callback(self._request)前面说了,.request_callback=Application()所以request_callback(self._request) = Application()(self._request)类被当做函数调用,所以__call__函数被调用了,就有了路由列表处理的操作,比较绕啊

    相关文章

      网友评论

        本文标题:tornado3第二部分分析tornado处理路由__call_

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