在 Django 中,中间件(Middleware)是处理 请求-响应过程中的钩子机制,位于 请求(request)和视图(view)之间,也可以位于 响应(response)和浏览器之间。通过中间件你可以对请求或响应进行统一的处理,如认证、日志、请求头修改、跨域处理、IP 限流等。
1.什么是中间件
中间件是一个类,它定义了一组钩子方法,用来在请求到达视图之前和响应返回客户端之前进行处理。
Django 会按顺序执行 MIDDLEWARE
列表中每一个中间件类。
2.中间件的生命流程
Browser → Request → Middleware → View → Response → Middleware → Browser
主要包括以下方法:
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 请求进入视图前处理
response = self.get_response(request)
# 响应返回客户端前处理
return response
def process_view(self, request, view_func, view_args, view_kwargs):
pass # 请求到达视图前执行(可拦截)
def process_exception(self, request, exception):
pass # 视图发生异常时调用
def process_template_response(self, request, response):
pass # 响应是 TemplateResponse 类型时调用
中间件钩子方法详细:
1. __call__(request)
作用:对所有请求前后做统一处理。
def __call__(self, request):
print("请求到达前")
response = self.get_response(request)
print("响应返回后")
return response
用场景:请求计时、响应日志、通用 token 验证等。
2.process_view(request, view_func, view_args, view_kwargs)
作用:在调用视图函数 之前,可以拦截、替换视图逻辑。
def process_view(self, request, view_func, view_args, view_kwargs):
if request.path.startswith("/admin/") and not request.user.is_authenticated:
return HttpResponse("未登录,禁止访问后台")
return None
常用场景:权限校验、登录验证、请求重定向等。
3.process_exception(request, exception)
作用:当视图函数抛出异常时调用,可拦截处理异常。
def process_exception(self, request, exception):
logger.error(f"异常发生:{exception}")
return HttpResponse("服务器内部错误,请稍后再试")
常用场景:统一错误页面、自定义错误日志记录。
4.process_template_response(request, response)
作用:对视图返回的 TemplateResponse
进行修改,比如加数据、模板扩展。
def process_template_response(self, request, response):
response.context_data['system_message'] = '系统运行良好'
return response
常用场景:模板全局变量注入、统一提示框处理等。
示例:自定义中间件完整代码
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse
class MyCustomMiddleware(MiddlewareMixin):
def process_request(self, request):
print(">>> 请求进入")
def process_view(self, request, view_func, view_args, view_kwargs):
print(f">>> 准备调用视图函数: {view_func.__name__}")
def process_exception(self, request, exception):
print(f">>> 捕获异常:{exception}")
return HttpResponse("自定义错误处理:程序出错了")
def process_template_response(self, request, response):
print(">>> 模板响应处理")
response.context_data['global_notice'] = '欢迎访问本站'
return response
def process_response(self, request, response):
print(">>> 响应返回")
return response
说明:从 Django 1.10 起推荐使用 __call__
模式;如果继承 MiddlewareMixin
,你就可以使用 process_xxx()
方式
注册中间件到项目
打开 settings.py
添加路径到 MIDDLEWARE
:
MIDDLEWARE = [
...
'myapp.middleware.MyCustomMiddleware',
]
1、process_request(self,request)
2、process_view(self, request, callback, callback_args, callback_kwargs)
3、process_template_response(self,request,response)
4、process_exception(self, request, exception)
5、process_response(self, request, response)
以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户
1、process_request和process_response
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
中间件使用实例:
第一步导入
from django.utils.deprecation import MiddlewareMixin
第二步:自定义中间件
from django.utils.deprecation import MiddlewareMixin#
from django.shortcuts import HttpResponse
#
class Md1(MiddlewareMixin):
#
def process_request(self,request):
print("Md1请求")
#
def process_response(self,request,response):
print("Md1返回")
return response
#
class Md2(MiddlewareMixin):
#
def process_request(self,request):
print("Md2请求")
#return HttpResponse("Md2中断")
def process_response(self,request,response):#
print("Md2返回")
return response
第三步:在view中定义一个视图函数(index)
def index(request):
print("view函数...")
return HttpResponse("OK")
第四步:在settings.py的MIDDLEWARE里注册自己定义的中间件
运行结果:
Md1请求#
Md2请求#
view函数...#
Md2返回#
Md1返回#
由此总结一下:
中间件的process_request方法是在执行视图函数之前执行的。
当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
不同中间件之间传递的request都是同一个对象
多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。
2、process_view
process_view(self, request, view_func, view_args, view_kwargs)
该方法有四个参数
request是HttpRequest对象。
view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args是将传递给视图的位置参数的列表(无名分组分过来的值).
view_kwargs是将传递给视图的关键字参数的字典(有名分组分过来的值)。 view_args和view_kwargs都不包含第一个视图参数(request)。
Django会在调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
1. process_request(self, request)
调用时机
在 Django 接收到 HTTP 请求并封装为 HttpRequest
对象后、URL Resolver(URL 解析)之前,依次调用项目中各个中间件的 process_request
。
方法签名
def process_request(self, request: HttpRequest) -> Optional[HttpResponse]:
...
参数
request
:Django 原生HttpRequest
对象。
返回值
返回
None
:继续执行后续中间件或最终视图。返回
HttpResponse
实例:短路,后续中间件的process_request
、process_view
、视图函数都不会再被调用,直接进入所有中间件的process_response
。
典型用途
统一鉴权:检查 Session、Token 或自定义 Header,若缺失或无效,直接返回
HttpResponseForbidden
。请求预处理:如给
request
附加属性、读取全局配置或打日志。跨域处理:早期设置 CORS 响应头(但推荐用专门包)。
class AuthMiddleware:
def process_request(self, request):
token = request.META.get("HTTP_X_API_TOKEN")
if token != settings.EXPECTED_TOKEN:
return HttpResponseForbidden("无效的 API Token")
# else: 无需返回,继续后续中间件 & 视图
2. process_view(self, request, view_func, view_args, view_kwargs)
调用时机
在 URL 解析完毕、找到要调用的视图函数(或类视图 as_view()
生成的函数)之后,真正执行视图前。
方法签名
def process_view(
self,
request: HttpRequest,
view_func: Callable,
view_args: Tuple,
view_kwargs: Dict
) -> Optional[HttpResponse]:
...
参数
view_func
:将要调用的视图函数(若是类视图,即该视图对应的可调用函数)。view_args
、view_kwargs
:URL 解析后将被传给视图函数的位置参数和关键字参数。
返回值
返回
None
:继续执行后续中间件或最终调用视图。返回
HttpResponse
:短路,不会调用视图本身,直接进入各中间件的process_response
。
典型用途
基于路由的权限/限流:不同路由使用不同权限检查或限流规则。
视图预修改:动态替换或包装
view_func
,比如给视图函数打补丁、注入共享资源。请求打标记:给
request
加上request._start_time = time.time()
,后面算耗时。
class TimingMiddleware:
def process_view(self, request, view_func, view_args, view_kwargs):
request._start_time = time.time()
3. process_template_response(self, request, response)
调用时机
视图函数执行并返回一个实现了 .render()
方法的响应对象(通常是 TemplateResponse
或其子类)后、调用 process_response
之前。
方法签名
def process_template_response(self, request: HttpRequest, response: TemplateResponse) -> TemplateResponse:
...
参数
response
:必须是TemplateResponse
或同样支持延迟渲染的对象。
返回值
必须返回一个同样可渲染的响应对象(可以是修改后的原
response
,也可以是一个全新实例)。
典型用途
全局上下文处理:给所有模板响应注入公共上下文变量,如站点导航、用户信息。
延迟渲染优化:在真正模板渲染前,动态切换模板引擎或主题。
class CommonContextMiddleware:
def process_template_response(self, request, response):
# 在所有模板上下文里添加 site_name
response.context_data['site_name'] = "我的站点"
return response
4. process_exception(self, request, exception)
调用时机
当视图函数或中间件的 process_view
抛出未捕获的异常时,Django 会倒序调用已经过的中间件的 process_exception
。
注意:如果
process_exception
返回HttpResponse
,则会停止后续异常处理逻辑,直接进入各中间件的process_response
。如果都返回
None
,则继续 Django 默认的错误处理(如 DEBUG 时展示追踪页)。
方法签名
def process_exception(self, request: HttpRequest, exception: Exception) -> Optional[HttpResponse]:
...
参数
exception
:视图或前置中间件抛出的异常实例。
返回值
返回
HttpResponse
:用此响应替代原本的错误页面或异常继续抛出;返回
None
:交由 Django 或其他中间件继续处理。
典型用途
全局日志:将异常信息上报到日志系统或外部监控(如 Sentry)。
自定义错误页:捕获特定异常类型后返回用户友好的错误页面。
class ExceptionLoggingMiddleware:
def process_exception(self, request, exception):
logger.error("Unhandled exception", exc_info=exception)
# 不返回 HttpResponse,继续 Django 默认流程
5. process_response(self, request, response)
调用时机
整个请求—视图—渲染流程结束后,得到一个 HttpResponse
,倒序经过所有中间件的 process_response
。
方法签名
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
...
参数
response
:视图或者process_exception
、process_template_response
返回的最终响应。
返回值
必须返回一个
HttpResponse
对象:可以是原对象、修改后的,或全新实例。
典型用途
统一响应头:添加/修改 CORS、缓存、加密签名等 HTTP Header。
后置日志:记录请求处理时长、HTTP 状态码、访问 IP 等。
内容压缩:对 HTML/JSON 响应进行 gzip 压缩(内建
GZipMiddleware
即此实现)。
class ResponseHeaderMiddleware:
def process_response(self, request, response):
response['X-Powered-By'] = 'Django'
return response
中间件调用顺序图示
请求进来
↓
┌─ process_request (M1)
│
├─ process_request (M2)
│
└─ process_request (M3)
↓
URL 解析 → 视图函数
↓
┌─ process_view (M1)
│
├─ process_view (M2)
│
└─ process_view (M3)
↓
视图执行
↓
视图返回 TemplateResponse?
├─ Yes → process_template_response (M1→M3)
└─ No
↓
↓(或上)
┌─ process_response (M3)
│
├─ process_response (M2)
│
└─ process_response (M1)
↓
返回客户端
异常分支:若视图或
process_view
抛异常,则倒序调用各中间件的process_exception
,如有返回则接着走process_response
。
视图或 process_view 抛 Exception
↓
┌─ M3.process_exception(request, exception)
│ ├─ 返回 HttpResponse? → 是 → 跳到 ↓③
│ └─ 返回 None → 继续
│
├─ M2.process_exception(request, exception)
│ ├─ 返回 HttpResponse? → 是 → 跳到 ↓③
│ └─ 返回 None → 继续
│
└─ M1.process_exception(request, exception)
├─ 返回 HttpResponse? → 是 → ↓③
└─ 返回 None → ↓①
① 默认异常处理(DEBUG:追踪;生产:500 页面)
↓
② Django 得到一个 HttpResponse(异常页或中间件产出)
↓
③ 依次调用:
M3.process_response(request, response)
M2.process_response(request, response)
M1.process_response(request, response)
↓
返回最终 response 给客户端
评论