关于django中间件执行过程

发布时间 2023-10-15 22:36:58作者: yx1257091748

众所周知,django的中间件一般有五个方法,常用的仅三个,示例如下

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse
中间件示例
class MyMiddleWare(MiddlewareMixin): 
	def process_request(self,request):
		pass
	def process_view(self,request):
		pass
	def process_response(view,request,response):
		pass
		# 少用,视图函数报错,会走这个方法
	def process_exception(self,request,excetion):
		print(excetion)
        return HttpResponse("服务器异常了")
		# 依旧少用
	def process_template_response(self,*args,**kwargs):
		pass

关于django请求的入口

本质上就是一个WSGIHandler() 对象

def get_wsgi_application():
    django.setup(set_prefix=False)
    return WSGIHandler()

django启动的时候对WSGIHandler 对象进行了实例化,会执行其构造方法, 而当用户请求到来的时候,会 引用这个对象() 会执行对应的__call__方法

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):
        ......

关于中间件的初始化加载:

关于wsgihandler对象的构造方法,它其实就两步,第一步掉用父类构造方法,第二步,执行self.load_middleware()方法,顾名思义,这个方法就是处理加载中间件的逻辑.

load_middleware() 加载逻辑之源码

def load_middleware(self, is_async=False):
	self._view_middleware = []
	self._template_response_middleware = []
	self._exception_middleware = []
# 这里是准备三个容器,来存放所有中间件的 process_view,process_template_response,process_exception三个方法。

#  三元表达式,如果是同步请求,则get_response  应该为 self._get_response
#  convert_exception_to_response 实际上就是在里面做了个闭包,把执行self._get_response方法进行了打包取名为inner函数返回给handler,后续如果希望执行self._get_response() 方法,直接handler()即可
	get_response = self._get_response_async if is_async else self._get_response
	handler = convert_exception_to_response(get_response)
	
	handler_is_async = is_async  # 这一步是处理异步逻辑的,暂且忽略

# 通过 reversed进行逆序 遍历配置文件中注册的所有中间件,并且通过import_string实现动态导入,然后通过反射,获取模块中的类。 本质上import_string内做了import_module方法导入和getattr反射。
	for middleware_path in reversed(settings.MIDDLEWARE):
		middleware = import_string(middleware_path)  # 所以此时,middleware表示遍历到的每一个
		......(此处省略对异步请求的逻辑处理)
		
		#  adapt_method_mode 方法接收了handler,对其进行了打包,最后还是把handler返回给了adapted_handler,所以此时可以把adapted_handler 直接理解为之前那个可以间接调用_get_response方法的handlerl。
		# mw_instance = middleware(adapted_handler)  因为middleware 是我们的中间件类,这里对其进行实例化,并且把adapted_handler也就是handler传递给其构造方法。最终应该是执行这些中间件类继承的MiddlewareMixin的构造方法。其构造方法,接收get_response形参也就是adapter_handler其实也就是handler 所以,后续如果mw_instance.get_response 其实就是在执行self._get_response()
		try:
			# Adapt handler, if needed.
			adapted_handler = self.adapt_method_mode(
				middleware_is_async,
				handler,
				handler_is_async,
				debug=settings.DEBUG,
				name="middleware %s" % middleware_path,
			)
			mw_instance = middleware(adapted_handler)
		except MiddlewareNotUsed as exc:
			......
			
		......
		

------------


		
这里三个反射,很明显,分别通过反射机制,从mw_instance这一中间件实例对象身上获取对应的
process_view,process_template_response,process_exception三方法,
将其放入之前准备好的三个容器中,值得注意的是,for遍历的时候进行了逆序,然后这里的process_view
是每次遍历到一个插入到第一个 ,另外两个是放到最后,所以最终结果应该是只有process_view
和配置文件中的顺序一致,另外俩是相反的
```python
		if hasattr(mw_instance, "process_view"):
			self._view_middleware.insert(
				0,
				self.adapt_method_mode(is_async, mw_instance.process_view),
			)
		if hasattr(mw_instance, "process_template_response"):
			self._template_response_middleware.append(
				self.adapt_method_mode(
					is_async, mw_instance.process_template_response
				),
			)
		if hasattr(mw_instance, "process_exception"):
			self._exception_middleware.append(
				self.adapt_method_mode(False, mw_instance.process_exception),
			)
	# convert_exception_to_response 刚说过,他本质上就是在做一个闭包,也就是通过调用handler可以间接的调用mw_instance ,而mw_instance 其实是handler 所以这里的handler还是handler
		handler = convert_exception_to_response(mw_instance)
		handler_is_async = middleware_is_async
			
			

至此,准备结束,此时,如果请求到来,会执行mw_instance(),而 mw_instance是中间件类的示例,所以它会执行中间件类中的__call__ 方法,分析如下图
image

#  此处的handler相当于具有三个功能 (执行process_request(),self._get_response(包括路由匹配和执行视图函数),执行process_response()) 
		handler = convert_exception_to_response(mw_instance)
		handler_is_async = middleware_is_async
			



至此第一个中间件准备ok
假设我们有ABCD 四个中间件,此时,A中间件加载完毕,假设 handler是这样的
[(A)process_request(),(A)get_response,(A)process_response()]

此时开始加载第二个中间件视线回到for循环
for middleware_path in reversed(settings.MIDDLEWARE):
		middleware = import_string(middleware_path)  # 所以此时,middleware表示遍历到的每一个
	try:
			# Adapt handler, if needed.
			adapted_handler = self.adapt_method_mode(
				middleware_is_async,
				handler,
				handler_is_async,
				debug=settings.DEBUG,
				name="middleware %s" % middleware_path,
			)
			mw_instance = middleware(adapted_handler)
	except MiddlewareNotUsed as exc:
值得注意的是,此处的handler,是第一个中间件的最后的handler
此时  adapted_handler = hander = [(A)process_request(),(A)get_response,(A)process_response()]
mw_instance = B( [(A)process_request(),(A)get_response,(A)process_response()]) 
mw_instance.get_response =  [(A)process_request(),(A)get_response,(A)process_response()]
mw_instance()  ==> [(B)process_request(),[(A)process_request(),(A)get_response,(A)process_response()],(B)process_response()]
逐层嵌套的图示

handler = D对象
		D对象()  触发call方法
		(D)process_request()
		get_response = C对象
		(D)process_response()
				执行call方法
				(C)process_request()
				get_response = B对象
				(C)process_response()
						执行call方法
						(B)process_request()
						get_response = A对象
						(B)process_response()
									执行call方法
									(A)process_request()
									get_response = self.get_resposne()  # 路由匹配,执行视图函数
									(A)process_response()