中间件是Django项目开发中高频使用的核心组件 —— 它既能实现全局请求拦截,又能避免业务代码侵入,是 Django 灵活性的关键体现。本文会从原理拆解到实战开发,带大家彻底掌握自定义中间件,即使是新手也能跟着步骤落地。
一、先搞懂:中间件到底是什么?
中间件是 Django 提供的「轻量级插件系统」,它能介入 HTTP 请求从接收→处理→响应的全生命周期,在全局范围内对请求 / 响应做统一处理,且无需修改视图、路由等核心业务代码。
举个实际项目中的例子:
如果需要对所有接口做「Token 验证」,你不需要在每个视图函数里写一遍 Token 校验逻辑 —— 只需写一个 Token 中间件,就能让所有请求在到达视图前先经过验证,无效 Token 直接返回 401,有效 Token 才放行到视图。
二、核心原理:中间件的「双向流动」机制
理解中间件的关键,在于搞懂请求和响应的「流动顺序」。这里用一个实际项目的 MIDDLEWARE
配置举例(包含 Django 内置中间件和自定义中间件):
# settings.py
MIDDLEWARE = [
# 内置中间件:安全相关处理(如 HTTPS 重定向)
"django.middleware.security.SecurityMiddleware",
# 内置中间件:会话管理(如 request.session)
"django.contrib.sessions.middleware.SessionMiddleware",
# 内置中间件:通用 HTTP 处理(如路径补全、反向解析)
"django.middleware.common.CommonMiddleware",
# 内置中间件:CSRF 防护
"django.middleware.csrf.CsrfViewMiddleware",
# 内置中间件:用户认证(如 request.user)
"django.contrib.auth.middleware.AuthenticationMiddleware",
# 自定义中间件:Token 验证(我们自己写的)
"myapp.middleware.TokenAuthMiddleware",
# 自定义中间件:请求耗时统计(我们自己写的)
"myapp.middleware.RequestTimeMiddleware",
]
基于这个配置,请求和响应的流动过程如下:
1. 请求阶段:「从上到下」的「放行链」
当客户端发送请求到 Django 服务器时,请求会按 MIDDLEWARE
列表的顺序,依次经过每个中间件,最终到达视图函数。
流程拆解:
客户端请求 → SecurityMiddleware → SessionMiddleware → CommonMiddleware → CsrfViewMiddleware → AuthenticationMiddleware → TokenAuthMiddleware → RequestTimeMiddleware → 视图函数
每个中间件在这个阶段的作用是「预处理请求」:
- 比如
SessionMiddleware
会从 Cookie 中读取 SessionID,把对应的会话数据挂载到request.session
; - 我们写的
TokenAuthMiddleware
会从请求头读取 Token,验证通过后才让请求继续往下走。
2. 响应阶段:「从下到上」的「加工链」
当视图函数处理完请求、返回响应后,响应会按 MIDDLEWARE
列表的逆序,再次经过每个中间件,最终返回给客户端。
流程拆解:
视图函数 → RequestTimeMiddleware → TokenAuthMiddleware → AuthenticationMiddleware → CsrfViewMiddleware → CommonMiddleware → SessionMiddleware → SecurityMiddleware → 客户端
每个中间件在这个阶段的作用是「后处理响应」:
- 比如
RequestTimeMiddleware
会计算请求总耗时,把耗时信息添加到响应头; SecurityMiddleware
会给响应添加X-Content-Type-Options
等安全头,防止浏览器漏洞。
3. 关键:中间件的「双方法约定」
为什么中间件能实现这种「双向流动」?核心是 Django 对中间件类有两个强制约定(固定语法):
1、__init__ 项目启动时(仅执行一次),用于初始化中间件,保存「下一个处理者」的引用。
2、__call__ 每次请求到达时,处理请求(前半段)、处理响应(后半段)
用伪代码理解这两个方法的协作:
# my_middleware.py
class CustomMiddleware:
def __init__(self, get_response):
# 项目启动时执行1次:保存「下一个中间件/视图」的引用
self.get_response = get_response
print("中间件初始化完成(仅执行1次)")
def __call__(self, request):
# 1. 请求阶段:每次请求都会执行(从上到下)
print("请求经过中间件:预处理请求")
# 关键:调用「下一个处理者」(传递请求)
response = self.get_response(request)
# 2. 响应阶段:每次响应都会执行(从下到上)
print("响应经过中间件:后处理响应")
return response # 返回处理后的响应
这里有个新手容易踩的坑:
__init__
是项目启动时执行,不是请求到达时执行!如果在 __init__
里写了「依赖请求的逻辑」(比如读取 request.META
),会直接报错 —— 因为初始化时根本没有 request
对象。
三、实战:实现一个自定义中间件demo
前置准备:项目结构
初始化一个新的Django工程
set_middlewareProject/ # 项目根目录(终端显示的顶层目录)
├─ set_middlewareProject/ # 项目核心配置目录(与项目同名,关键!)
│ ├─ __pycache__/ # Python编译缓存目录(自动生成,无需修改)
│ ├─ __init__.py # 空文件,标记该目录为Python包
│ ├─ asgi.py # ASGI协议配置(部署用,暂不涉及)
│ ├─ settings.py # 项目配置文件(需在这里注册中间件)
│ ├─ urls.py # 项目URL路由配置
│ └─ wsgi.py # WSGI协议配置(部署用,暂不涉及)
├─ templates/ # 模板文件目录(若用模板渲染,暂不涉及中间件)
├─ db.sqlite3 # Django默认SQLite数据库文件(自动生成)
└─ manage.py # Django项目命令行工具(启动、创建应用等)
启动服务
步骤 1:编写中间件代码
新建一个.py文件设置自定义中间件:
# my_middleware.py
class CustomMiddleware:
def __init__(self,get_response):
self.get_response = get_response
def __call__(self,request):
# 在视图处理请求之前的逻辑
print("在视图处理请求之前,中间件先对请求进行预处理")
response = self.get_response(request)
# 在视图处理请求之后的逻辑
print("在视图处理请求之后,在响应发出去之前对响应进行操作")
return response
注:自定义中间件需要按固定结构写:
class 中间件类名:
def __init__(self, get_response):
self.get_response = get_response # 固定逻辑
def __call__(self, request):
# 处理请求(可选)
response = self.get_response(request) # 固定逻辑
# 处理响应(可选)
return response # 固定逻辑
步骤 2:注册中间件
在 settings.py
的 MIDDLEWARE
列表中添加该中间件。
步骤 3:测试效果
启动服务,通过浏览器访问服务查看控制台响应结果:
请求处理过程:
请求 → SecurityMiddleware → SessionMiddleware → CommonMiddleware → ... →
你的自定义中间件 → 视图函数
响应处理过程:
视图函数 → 你的自定义中间件 → ... → CommonMiddleware → SessionMiddleware → SecurityMiddleware → 返回给客户端
回到自定义中间件文件添加更多处理逻辑:
# my_middleware.py
class CustomMiddleware:
def __init__(self,get_response):
self.get_response = get_response
def __call__(self,request):
# 在视图处理请求之前的逻辑
print("在视图处理请求之前,中间件先对请求进行预处理")
print(f'request.path: {request.path}')
response = self.get_response(request)
# 在视图处理请求之后的逻辑
print("在视图处理请求之后,在响应发出去之前对响应进行操作")
print(f'response.status_code: {response.status_code}')
# 可以修改响应内容
response.content = "<h1>这是中间件修改后的响应内容</h1>"
return response
重新启动服务器查看响应结果:
此时可以看到控制台打印了我们新增的输出信息,并且在浏览器上显示的是我们在response返回前更改的内容。到这里,这个例子就完成了。
四、总结
中间件是 Django 生态中极具灵活性的组件,核心价值在于「全局统一处理,不侵入业务代码」。掌握它的关键是:
- 理解「请求从上到下、响应从下到上」的流动机制;
- 遵守
__init__
和__call__
的固定语法; - 实战中注意中间件顺序和白名单设计。
后续你可以基于本文的思路,扩展更多实用中间件:比如「IP 黑名单拦截」「请求参数日志打印」「响应数据压缩」等,进一步提升项目的可维护性。