首页 > 其他 > 详细

tornado3第二部分分析tornado处理路由__call__()

时间:2014-08-01 07:04:12      阅读:434      评论:0      收藏:0      [点我收藏+]

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__函数被调用了,就有了路由列表处理的操作,比较绕啊


看起来比较多,你可以借助python的pdb模块断点调试,就晓得tornado一个request的请求过程

本文出自 “lpj24” 博客,请务必保留此出处http://6167018.blog.51cto.com/6157018/1533449

tornado3第二部分分析tornado处理路由__call__(),布布扣,bubuko.com

tornado3第二部分分析tornado处理路由__call__()

原文:http://6167018.blog.51cto.com/6157018/1533449

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!