整個流程如以下圖所示,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的結構,而後逐步細細分析每一步。