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) # type: ignore
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:
# 调用父类的serve_forever,即BaseServer.serve_forever
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)
# bpo-35017: shutdown() called during select(), exit immediately.
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) # 处理request
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(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) # 调用finish_request
self.shutdown_request(request)
def finish_request(self, request, client_address):
# 最重要的一步。
# 这里的RequestHandlerClass在Flask中默认是WSGIRequestHandler
# 传递的值分别是request请求, client_address地址和self(即BaseWSGIServer实例)
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:
# 最重要的一步,调用了WSGIRequestHandler.handle函数。
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:
# 这里的self是WSGIRequestHandler实例,跟进
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):
# 这里的self是WSGIRequestHandler实例
"""Handle multiple requests if necessary."""
self.close_connection = True
self.handle_one_request()# 处理一个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
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:
...# 往socket中写入response
self.wfile.write(data)
self.wfile.flush()
def start_response(status, headers, exc_info=None): # type: ignore
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:
# 调用Flask.__call__(self, environ, start_response)
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() # type: ignore
try:
execute(self.server.app) # self.server.app就是Flask的实例
except (ConnectionError, socket.timeout) as e:
self.connection_dropped(e, environ)
except ...
...
总结
总的来说就是通过使用werkzeug
来代理一个Server
,使用WSGIRequestHandler
调用到Flask.__call__
函数,然后获取返回值,再通过socket
返回到客户端。