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