Django源码解读之MIddleware(中间件)
主程序入口django\core\management\commands\runserver.py
1.inner_run()
2.run()
3.再执行socketserver.py BaseServerserve_forever()
#django\core\management\commands\runserver.py
def inner_run(self, *args, **options):
....
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
except OSError as e:
....
# django\core\servers\basehttp.py
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
server_address = (addr, port)
if threading:
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
else:
httpd_cls = server_cls
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
# ThreadingMixIn.daemon_threads indicates how threads will behave on an
# abrupt shutdown; like quitting the server by the user or restarting
# by the auto-reloader. True means the server will not wait for thread
# termination before it quits. This will make auto-reloader faster
# and will prevent the need to kill the server manually if a thread
# isn't terminating correctly.
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()
# socketserver.py
class BaseServer:
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()
# serve_forever self._handle_request_noblock() -> process_request
执行BaseServer._handle_request_noblock() -> BaseServer.process_request->BaseServerfinish_request
serve_forever self._handle_request_noblock() -> process_request->finish_request
def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)
RequestHandlerClass 就是WSGIRequestHandler,将其实例化
实例化是执行self.handle()
和self.finish()
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()
执行的是子类的handle
1.WSGIRequestHandler.handle()
2.WSGIRequestHandler.handle_one_request()
3.BaseHandler.run()
# django.core.servers.basehttp.py
WSGIRequestHandler.handle()
WSGIRequestHandler.handle_one_request()
# application = self.server.get_app() = wsgi_handler = WSGIHandler()
def handle(self):
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
try:
self.connection.shutdown(socket.SHUT_WR)
except (AttributeError, OSError):
pass
def handle_one_request(self):
"""Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
if not self.parse_request(): # An error code has been sent, just exit
return
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging & connection closing
handler.run(self.server.get_app())
# ServerHandler(simple_server.ServerHandler)继承ServerHandler(SimpleHandler)继承SimpleHandler(BaseHandler)
# python3.7.5\Lib\wsgiref\handlers.py(python标准库)
class BaseHandler:
def run(self, application):
try:
self.setup_environ()
self.result = application(self.environ, self.start_response) # application 就是WSGIRequestHandler
由上述self.result = application(self.environ, self.start_response)
最后还是执行 application 就是WSGIRequestHandler实例的__call__()
方法
最终执行WSGIHandler的__call__()
方法
- request = self.request_class(environ) # HttpRequest
- response = self.get_response(request) # HttpResponse 重点看这个执行函数,里面包含中间件的执行
- 执行的get_response里面的self._middleware_chain(request)
- _middleware_chain就是中间件链,最内层的方法就是_get_response()
代码如下
# django.core.handlers.wsgi.py
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware()
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ) # 发送信号对应的connect回处理函数
request = self.request_class(environ) # HttpRequest
response = self.get_response(request) # HttpResponse 重点看这个执行函数,里面包含中间件的执行
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = [
*response.items(),
*(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
]
start_response(status, response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
# If `wsgi.file_wrapper` is used the WSGI server does not call
# .close on the response, but on the file wrapper. Patch it to use
# response.close instead which takes care of closing all files.
response.file_to_stream.close = response.close
response = environ['wsgi.file_wrapper'](response.file_to_stream, response.block_size)
return response
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRequest."""
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF)
response = self._middleware_chain(request)
response._resource_closers.append(request.close)
if response.status_code >= 400:
log_response(
'%s: %s', response.reason_phrase, request.path,
response=response,
request=request,
)
return response
# 真个最核心的就是这个方法,该方法才是依据路由,匹配到视图函数,返回响应
def _get_response(self, request):
"""
Resolve and call the view, then apply view, exception, and
template_response middleware. This method is everything that happens
inside the request/response middleware.
"""
response = None
callback, callback_args, callback_kwargs = self.resolve_request(request) # 依据请求路由返回视图函数arg,kwargs参数
# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
break
if response is None:
wrapped_callback = self.make_view_atomic(callback)
# If it is an asynchronous view, run it in a subthread.
if asyncio.iscoroutinefunction(wrapped_callback):
wrapped_callback = async_to_sync(wrapped_callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs) # 调用视图函数,返回HTTPResponse对象
except Exception as e:
response = self.process_exception_by_middleware(e, request)
if response is None:
raise
# Complain if the view returned None (a common error).
self.check_response(response, callback)
# If the response supports deferred rendering, apply template
# response middleware and then render the response
if hasattr(response, 'render') and callable(response.render):
for middleware_method in self._template_response_middleware:
response = middleware_method(request, response)
# Complain if the template response middleware returned None (a common error).
self.check_response(
response,
middleware_method,
name='%s.process_template_response' % (
middleware_method.__self__.__class__.__name__,
)
)
try:
response = response.render()
except Exception as e:
response = self.process_exception_by_middleware(e, request)
if response is None:
raise
return response
上述_get_response
方法中通过resolve_request
来匹配路由返回对应的视图函数和请求参数
最终response = wrapped_callback(request, *callback_args, **callback_kwargs)
执行返回响应