tornado-業務流程

整個流程如以下圖所示,python


上圖涉及到了多個類,下面就講解主要的代碼步驟ios


首先HTTPServe繼承TcpServer,複寫了handle_stream方法,當底層每次有新的請求鏈接時,就會調用。cookie

def handle_stream(self, stream, address):
        context = _HTTPRequestContext(stream, address,
                                      self.protocol)
        conn = HTTP1ServerConnection(
            stream, self.conn_params, context)
        self._connections.add(conn)
        conn.start_serving(self)

_HTTPRequestContext類是用來解析ip地址,協議的。app

而後實例化HTTPServerConnection類,這個類主要負責對鏈接的處理。最後調用conn.start_serving方法。異步

def start_serving(self, delegate):
        """Starts serving requests on this connection.

        :arg delegate: a `.HTTPServerConnectionDelegate`
        """
        assert isinstance(delegate, httputil.HTTPServerConnectionDelegate)
        self._serving_future = self._server_request_loop(delegate)
        # Register the future on the IOLoop so its errors get logged.
        self.stream.io_loop.add_future(self._serving_future,
                                       lambda f: f.result())

    @gen.coroutine
    def _server_request_loop(self, delegate):
        try:
            while True:
                conn = HTTP1Connection(self.stream, False,
                                       self.params, self.context)
                request_delegate = delegate.start_request(self, conn)
                try:
                    ret = yield conn.read_response(request_delegate)
                except (iostream.StreamClosedError,
                        iostream.UnsatisfiableReadError):
                    return
                except _QuietException:
                    # This exception was already logged.
                    conn.close()
                    return
                except Exception:
                    gen_log.error("Uncaught exception", exc_info=True)
                    conn.close()
                    return
                if not ret:
                    return
                yield gen.moment
        finally:
            delegate.on_close(self)

能夠看到start_serving方法,主要是調用了_server_request_loop方法。_server_request_loop方法被gen.coroutine裝飾,說明這個函數是異步調用。函數

主要delegate這個函數參數,它指向HTTPServer。這裏須要說明下一,HTTPServer和Application是怎麼聯繫的。tornado

由上圖能夠看出_ServerRequestAdapter類是_RequestDispatcher類的代理。HTTPServer和Application是經過這兩個類關聯一塊兒的。oop


繼續回到_server_request_loop函數裏。它首先實例化了HTTP1Connection類,而後等帶conn.read_response方法,返回結果。ui

繼續看HTTP1Connection的read_response方法:this

def read_response(self, delegate):
        """Read a single HTTP response.

        Typical client-mode usage is to write a request using `write_headers`,
        `write`, and `finish`, and then call ``read_response``.

        :arg delegate: a `.HTTPMessageDelegate`

        Returns a `.Future` that resolves to None after the full response has
        been read.
        """
        if self.params.decompress:
            delegate = _GzipMessageDelegate(delegate, self.params.chunk_size)
        return self._read_message(delegate)

這裏_GzipMessageDelegate是一個裝飾類(裝飾者模式),負責內容的gzip解碼。

_read_message代碼比較多,注意分爲幾個部分,一是讀取http的首部,而後調用delegate.header_received。

而後讀取http的body,最後調用delegate.finish。下面簡化下代碼

#試圖從stream讀取到連續兩個行結束符。由於連續兩個行結束符意味着HEADER部分已經完成
header_future = self.stream.read_until_regex(
                b"\r?\n\r?\n",
                max_bytes=self.params.max_header_size)
#解析首部
start_line, headers = self._parse_headers(header_data)     

#調用delegate.header_received
delegate.headers_received(start_line, headers)

#試圖讀取body
body_future = self._read_body(
                    start_line.code if self.is_client else 0, headers, delegate)       

#調用delegate.finish                    
delegate.finish()


接下來看看_RequestDispatcher的實現,他負責主要的邏輯。

def headers_received(self, start_line, headers):
        self.set_request(httputil.HTTPServerRequest(
            connection=self.connection, start_line=start_line, headers=headers))
        if self.stream_request_body:
            self.request.body = Future()
            return self.execute()

    def set_request(self, request):
        self.request = request
        self._find_handler()
        self.stream_request_body = _has_stream_request_body(self.handler_class)

header_received會實例化HTTPServerRequest,這個對象就是RequestHandler的request屬性。

_find_handler就是調用Application的_get_host_handlers方法,找到相應的RequestHandler的子類。


def finish(self):
        if self.stream_request_body:
            self.request.body.set_result(None)
        else:
            self.request.body = b''.join(self.chunks)
            self.request._parse_body()
            self.execute()

這裏self.stream_request_body,只有在相應的RequestHandler被stream_request_body裝飾,纔會返回True。

因此這裏會執行self.excute()方法。

def execute(self):
        # 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.application.settings.get("compiled_template_cache", True):
            with RequestHandler._template_loader_lock:
                for loader in RequestHandler._template_loaders.values():
                    loader.reset()
        if not self.application.settings.get('static_hash_cache', True):
            StaticFileHandler.reset()

        self.handler = self.handler_class(self.application, self.request,
                                          **self.handler_kwargs)
        transforms = [t(self.request) for t in self.application.transforms]

        if self.stream_request_body:
            self.handler._prepared_future = Future()
        # Note that if an exception escapes handler._execute it will be
        # trapped in the Future it returns (which we are ignoring here).
        # However, that shouldn't happen because _execute has a blanket
        # except handler, and we cannot easily access the IOLoop here to
        # call add_future (because of the requirement to remain compatible
        # with WSGI)
        f = self.handler._execute(transforms, *self.path_args, **self.path_kwargs)
        f.add_done_callback(lambda f: f.exception())
        # If we are streaming the request body, then execute() is finished
        # when the handler has prepared to receive the body.  If not,
        # it doesn't matter when execute() finishes (so we return None)
        return self.handler._prepared_future

注意到這幾步驟,

#實例化RequestHandler的子類
self.handler = self.handler_class(self.application, self.request,
                                          **self.handler_kwargs)
#包裝request,用於http中傳輸                                         
transforms = [t(self.request) for t in self.application.transforms] 

#調用RequestHandler的_execute方法
self.handler._execute(transforms, *self.path_args, **self.path_kwargs)


最後來看看Requesthandler的_execute方法:

@gen.coroutine
    def _execute(self, transforms, *args, **kwargs):
        """Executes this request with the given output transforms."""
        self._transforms = transforms
        try:
            if self.request.method not in self.SUPPORTED_METHODS:
                raise HTTPError(405)
            self.path_args = [self.decode_argument(arg) for arg in args]
            self.path_kwargs = dict((k, self.decode_argument(v, name=k))
                                    for (k, v) in kwargs.items())
            # If XSRF cookies are turned on, reject form submissions without
            # the proper cookie
            if self.request.method not in ("GET", "HEAD", "OPTIONS") and \
                    self.application.settings.get("xsrf_cookies"):
                self.check_xsrf_cookie()

            result = self.prepare()
            if is_future(result):
                result = yield result
            if result is not None:
                raise TypeError("Expected None, got %r" % result)
            if self._prepared_future is not None:
                # Tell the Application we've finished with prepare()
                # and are ready for the body to arrive.
                self._prepared_future.set_result(None)
            if self._finished:
                return

            if _has_stream_request_body(self.__class__):
                # In streaming mode request.body is a Future that signals
                # the body has been completely received.  The Future has no
                # result; the data has been passed to self.data_received
                # instead.
                try:
                    yield self.request.body
                except iostream.StreamClosedError:
                    return

            method = getattr(self, self.request.method.lower())
            result = method(*self.path_args, **self.path_kwargs)
            if is_future(result):
                result = yield result
            if result is not None:
                raise TypeError("Expected None, got %r" % result)
            if self._auto_finish and not self._finished:
                self.finish()
        except Exception as e:
            self._handle_request_exception(e)
            if (self._prepared_future is not None and
                    not self._prepared_future.done()):
                # In case we failed before setting _prepared_future, do it
                # now (to unblock the HTTP server).  Note that this is not
                # in a finally block to avoid GC issues prior to Python 3.4.
                self._prepared_future.set_result(None)


注意這幾個步驟:

#調用prepare
result = self.prepare()

#找到相應的方法,而且調用
method = getattr(self, self.request.method.lower())
result = method(*self.path_args, **self.path_kwargs)

#自動調用self.finish
if self._auto_finish and not self._finished:
                self.finish()


從Http請求過來,tornado會進行相應的處理。根據上面的流程,就能夠比較清楚的弄清tornado的結構,而後逐步細細分析每一步。

相關文章
相關標籤/搜索