1 中间件的五个方法
- process_request(self,request)
- process_response(self, request, response)
- process_view(self, request, view_func, view_args, view_kwargs)
- process_exception(self, request, exception)
- process_template_response(self,request,response)
中间件处理函数 | 什么时候执行 | 执行顺序 | 返回值 |
---|---|---|---|
process_request | 收到请求,未进行路由匹配 | 从顶至低 | None或者HttpResponse对象 |
process_response | 视图执行完毕,返回响应时前 | 从低至顶 | HttpResponse对象 |
process_view | 进行路由匹配完成,执行视图函数之前 | 从顶至低 | None或者HttpResponse对象 |
process_exception | 视图执行中发生异常时 | 从低至顶 | None或者HttpResponse对象 |
process_template_response | 视图刚执行完毕,进入process_response之前 | 从低至顶 | 实现了render方法的响应对象 |
2 中间件的执行流程
-
路由还未匹配时自顶而下执行中间价中的request
-
匹配到路由后还未执行视图函数时,自顶而下执行view函数
-
执行视图函数,返回response
-
当视图函数返回时,自低而上执行中间件response
如果每层执行过程中出现问题获取拒绝执行,如request中返回Httpresponse或出现异常,会直接跳到exception或respon,不会继续执行request和view。
3 中间件如何使用
- 新建一个mideleware的文件夹
- 在middleware创建不同功能的middleware.py文件
- 在middleware.py文件中根据功能些Middleware类继承MiddlewareMixin
- 在setting.py文件中的MIDDLEWARE列表中,添加的样式为middleware文件夹.middleware.py文件.middleware类
# testMiddleware.py
from django.utils.deprecation import MiddlewareMixin
from django.http.response import JsonResponse
class Middleware1(MiddlewareMixin):
def process_request(self, request):
print("Middleware1->process_request")
def process_view(self, request, view_func, view_args, view_kwargs):
print("Middleware1->process_view")
def process_response(self, request, response):
print("Middleware1->process_response")
return response
def process_exception(self, request, exception):
print("Middleware1->process_exception")
def process_template_response(self, request, response):
print("Middleware1->rocess_template_response")
return responce
class Middleware2(MiddlewareMixin):
def process_request(self, request):
print("Middleware2->process_request")
def process_view(self, request, view_func, view_args, view_kwargs):
print("Middleware2->process_view")
def process_response(self, request, response):
print("Middleware2->process_response")
return response
def process_exception(self, request, exception):
print("Middleware2->process_exception")
def process_template_response(self, request, response):
print("Middleware2->rocess_template_response")
return responce
class Middleware3(MiddlewareMixin):
def process_request(self, request):
print("Middleware3->process_request")
def process_view(self, request, view_func, view_args, view_kwargs):
print("Middleware3->process_view")
def process_response(self, request, response):
print("Middleware3->process_response")
return response
def process_exception(self, request, exception):
print("Middleware3->process_exception")
def process_template_response(self, request, response):
print("Middleware3->rocess_template_response")
return responce
# urls.py
from django.contrib import admin
from django.urls import path
from django.http.response import JsonResponse
from django.shortcuts import HttpResponse
def home(request):
print("view->home")
return JsonResponse({"message": "hell world"})
urlpatterns = [
path('admin/', admin.site.urls),
path("home/", home, name="home")
]
# setting.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"middleware.testMiddleware.Middleware1",
"middleware.testMiddleware.Middleware2",
"middleware.testMiddleware.Middleware3",
]
访问/home网址,界面打印
4 中间件执行的各种情况
1 request中被中断, 当中间件中的request中返回了一个httpresponse时,中间件将被中断,不会执行继续执行中间件,直接跳转到对应中间的process_response中执行
# 中间件2中process_request返回HttpResponce
....
class Middleware2(MiddlewareMixin):
def process_request(self, request):
print("Middleware2->process_request")
return JsonResponse({"message": "middleware"})
......
中间件2中process_request直接返回HttpResponce时,跳过下面中间件和视图函数直接执行中间件2的process_response
2 view中被中断,单view中返回一个httpresponce时,会立即进入response中间中, 跳过其他中间件和视图函数
# 中间件2返回httpresponce
class Middleware2(MiddlewareMixin):
.....
def process_view(self, request, view_func, view_args, view_kwargs):
print("Middleware2->process_view")
return JsonResponse({"message": "middleware"})
......
中间件2的process_view返回了HttpResponce时,跳过下面中间和视图函数直接执行中间件3的process_responce
3 当视图中出现异常时, 会直接跳转到exception中,执行顺序是从低而上
# 模拟视图出现异常
def home(request):
1/0
print("view->home")
return JsonResponse({"message": "hell world"})
当视图中的出现异常的话直接跳转到中间件3的process_exception中,如果process_exception中没有处理这个错误这个错误会一直沿着中间返回到前端。
4 当视图中出现异常时, exception 有错误的处理,将跳出exception执行到responce中
# 模拟异常处理
class Middleware3(MiddlewareMixin):
....
def process_exception(self, request, exception):
print("Middleware3->process_exception")
# 模拟异常处理
return JsonResponse({})
...
视图函数中出现异常,异常被中间件3处理就不会执行其他的exception。
5 中间件的实现原理
在Django源码中,中间件的实现原理主要体现在Django的django.core.handlers.base
模块中,特别是BaseHandler
类和其子类WSGIHandler
。Django的请求/响应处理流程中,中间件是通过这些类和它们的方法来管理和调用的。
以下是Django中间件实现原理的源码分析:
- 中间件的加载:
在Django启动时,它会从settings.py
文件中的MIDDLEWARE
设置中加载中间件类,并创建一个中间件实例列表。 - 请求处理流程:
当Django接收到一个WSGI请求时,它首先会创建一个WSGIRequest
对象来表示这个请求,然后开始处理流程。 - 调用中间件的
process_request
方法:
在WSGIHandler
类的_get_response
方法中,Django会遍历中间件实例列表,并调用每个中间件的process_request
方法。如果这个方法返回了一个HttpResponse
对象,则处理流程会立即停止,并返回这个响应给客户端。
class MiddlewareMixin:
sync_capable = True
async_capable = True
# RemovedInDjango40Warning: when the deprecation ends, replace with:
# def __init__(self, get_response):
def __init__(self, get_response=None):
self.get_response = get_response
super().__init__()
def __call__(self, request):
# Exit out to async mode, if needed
if asyncio.iscoroutinefunction(self.get_response):
return self.__acall__(request)
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
response = response or self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
def _get_response_none_deprecation(self, get_response):
if get_response is None:
warnings.warn(
'Passing None for the middleware get_response argument is '
'deprecated.',
RemovedInDjango40Warning, stacklevel=3,
)
def _get_response(self, request):
response = None
# Apply request middleware
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response:
break
这里的self._request_middleware
是一个包含中间件process_request
方法的列表。
-
执行视图函数:
如果所有中间件的process_request
方法都成功执行完毕,Django会调用resolver.resolve404()
来获取匹配的视图函数,并执行它。 -
调用中间件的
process_response
方法:
视图函数执行完毕后,Django会开始调用中间件的process_response
方法。这些方法是按照与process_request
相反的顺序调用的,以确保按照正确的顺序处理响应。response = response_middleware(request, response)
在
WSGIHandler
类的_get_response
方法中,Django会遍历一个包含process_response
方法的中间件列表,并将请求和视图函数返回的响应作为参数传递给每个方法。每个方法都可以修改或替换响应对象。 -
返回响应:
最后,经过所有中间件的process_response
方法处理后,Django会将最终的HttpResponse
对象发送给客户端。
在源码级别,中间件的执行逻辑是嵌套在请求/响应处理流程中的。Django通过维护中间件列表和调用相应的方法,确保请求在到达视图之前和响应在返回客户端之前都能经过中间件的处理。
此外,Django的中间件机制还考虑了一些异常处理和清理工作,以确保即使在中间件或视图函数中发生异常时,也能正确执行清理操作(如关闭数据库连接等)。这些逻辑通常位于BaseHandler
类的_get_response
方法的异常处理部分。
总体来说,Django的中间件实现原理体现了其请求/响应处理流程的灵活性和可扩展性,允许开发者在关键点上插入自定义逻辑,以实现各种功能需求。