Flask 接收请求的流程
Flask 是基于werkzeug 包实现的。
来研究一下,request 是如何通过werkzeug 传递给Flask 的。
同时研究一下BaseServer 的serve_forever 。
BaseWSGIServer
BaseWSGIServer 是werkzeug 的一个类,继承了HTTPServer class BaseWSGIServer(HTTPServer)
首先查看构造函数
BaseWSGIServer 的__init__
def __init__(
self,
host: str,
port: int,
app: "WSGIApplication",
handler: t.Optional[t.Type[WSGIRequestHandler]] = None,
passthrough_errors: bool = False,
ssl_context: t.Optional[_TSSLContextArg] = None,
fd: t.Optional[int] = None,
) -> None:
if handler is None:
handler = WSGIRequestHandler
...
super().__init__(server_address, handler)
self.app = app
self.passthrough_errors = passthrough_errors
self.shutdown_signal = False
self.host = host
self.port = self.socket.getsockname()[1]
...
def log(self, type: str, message: str, *args: t.Any) -> None:
_log(type, message, *args)
def serve_forever(self, poll_interval: float = 0.5) -> None:
self.shutdown_signal = False
try:
super().serve_forever(poll_interval=poll_interval)
except KeyboardInterrupt:
pass
finally:
self.server_close()
def handle_error(self, request: t.Any, client_address: t.Tuple[str, int]) -> None:
if self.passthrough_errors:
raise
return super().handle_error(request, client_address)
BaseWSGIServer 的serve_forever
def serve_forever(self, poll_interval: float = 0.5) -> None:
self.shutdown_signal = False
try:
super().serve_forever(poll_interval=poll_interval)
except KeyboardInterrupt:
pass
finally:
self.server_close()
BaseServer.serve_forever
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if self.__shutdown_request:
break
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
BaseServer._handle_request_noblock
class BaseServer:
...
def __init__(self, server_address, RequestHandlerClass):
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
...
def _handle_request_noblock(self):
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
def process_request(self, request, client_address):
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self)
def shutdown_request(self, request):
self.close_request(request)
WSGIRequestHandler
WSGIRequestHandler 没有__init__ 函数,跟踪父类**BaseRequestHandler **
class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
在werkzeug 包中,WSGIRequestHandler 继承了BaseRequestHandler ,也就是调用WSGIRequestHandler.handle()
WSGIRequestHandler.handle()
def handle(self) -> None:
"""Handles a request ignoring dropped connections."""
try:
BaseHTTPRequestHandler.handle(self)
except (ConnectionError, socket.timeout) as e:
self.connection_dropped(e)
except Exception as e:
if self.server.ssl_context is not None and is_ssl_error(e):
self.log_error("SSL error occurred: %s", e)
else:
raise
if self.server.shutdown_signal:
self.initiate_shutdown()
BaseHTTPRequestHandler.handle(self)
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
WSGIRequestHandler.handle_one_request()
def handle_one_request(self) -> None:
"""Handle a single HTTP request."""
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = True
elif self.parse_request():
self.run_wsgi()
run_wsgi
def run_wsgi(self) -> None:
if self.headers.get("Expect", "").lower().strip() == "100-continue":
self.wfile.write(b"HTTP/1.1 100 Continue\r\n\r\n")
self.environ = environ = self.make_environ()
status_set: t.Optional[str] = None
headers_set: t.Optional[t.List[t.Tuple[str, str]]] = None
status_sent: t.Optional[str] = None
headers_sent: t.Optional[t.List[t.Tuple[str, str]]] = None
def write(data: bytes) -> None:
...
self.wfile.write(data)
self.wfile.flush()
def start_response(status, headers, exc_info=None):
nonlocal status_set, headers_set
if exc_info:
try:
if headers_sent:
raise exc_info[1].with_traceback(exc_info[2])
finally:
exc_info = None
elif headers_set:
raise AssertionError("Headers already set")
status_set = status
headers_set = headers
return write
def execute(app: "WSGIApplication") -> None:
application_iter = app(environ, start_response)
try:
for data in application_iter:
write(data)
if not headers_sent:
write(b"")
finally:
if hasattr(application_iter, "close"):
application_iter.close()
try:
execute(self.server.app)
except (ConnectionError, socket.timeout) as e:
self.connection_dropped(e, environ)
except ...
...
总结
总的来说就是通过使用werkzeug 来代理一个Server ,使用WSGIRequestHandler 调用到Flask.__call__ 函数,然后获取返回值,再通过socket 返回到客户端。
|