一、什么是Django中间件
想象一下你每天上班要经过的安检通道,所有进入大楼的人都要先经过安检,这就是中间件的作用。在Django中,中间件就像是请求和响应之间的安检通道,每个请求和响应都会经过这些通道。
中间件本质上是一个轻量级的插件系统,可以全局改变Django的输入和输出。它位于Django处理请求和响应的核心流程中,能够拦截所有经过Django的请求和响应。
二、为什么要自定义中间件
假设我们需要实现以下功能:
- 记录每个请求的处理时间
- 检查所有请求是否携带特定header
- 对所有响应统一添加CORS头
- 对特定路径的请求进行预处理
这些需求如果放在视图函数中处理,会导致大量重复代码。中间件正是解决这类问题的完美方案,它让我们可以在一个地方集中处理这些逻辑。
三、如何编写自定义中间件
让我们通过一个完整示例来学习。下面是一个记录请求处理时间的中间件:
# 技术栈: Django 4.2
import time
from django.utils.deprecation import MiddlewareMixin
class RequestTimeMiddleware(MiddlewareMixin):
"""
记录请求处理时间的中间件
1. 在请求开始时记录时间
2. 在响应结束时计算处理耗时
3. 将耗时信息添加到响应头中
"""
def process_request(self, request):
# 在请求开始时记录当前时间
request.start_time = time.time()
return None
def process_response(self, request, response):
# 计算请求处理总耗时(毫秒)
duration = round((time.time() - request.start_time) * 1000, 2)
# 将耗时信息添加到响应头
response['X-Request-Duration'] = f"{duration}ms"
return response
这个中间件做了三件事:
- 在请求到达时记录开始时间
- 在响应返回时计算耗时
- 将耗时信息添加到响应头
四、中间件的五种钩子方法
Django中间件提供了五个关键方法,对应请求/响应处理的不同阶段:
process_request- 请求到达视图前process_view- 路由找到视图后,执行视图前process_template_response- 视图返回模板响应后process_exception- 视图抛出异常时process_response- 响应返回客户端前
下面是一个使用多个钩子的完整示例:
# 技术栈: Django 4.2
from django.http import JsonResponse
class AuthCheckMiddleware(MiddlewareMixin):
"""
综合认证检查中间件
1. 检查请求头中的API-KEY
2. 记录未认证访问尝试
3. 对特定路径跳过检查
"""
WHITELIST_PATHS = ['/api/public/', '/healthcheck/']
def process_request(self, request):
# 跳过白名单路径
if any(request.path.startswith(p) for p in self.WHITELIST_PATHS):
return None
# 检查API-KEY头
api_key = request.headers.get('API-KEY')
if not api_key or api_key != 'SECRET_KEY_123':
# 记录未认证访问
print(f"Unauthorized access attempt to {request.path}")
return JsonResponse({'error': 'Invalid API Key'}, status=401)
return None
def process_view(self, request, view_func, view_args, view_kwargs):
# 可以在这里获取视图的更多信息
print(f"Accessing view: {view_func.__name__}")
return None
五、中间件的执行顺序
中间件的执行顺序很重要,它取决于MIDDLEWARE配置中的顺序。Django会按照以下顺序执行:
- 请求阶段:
MIDDLEWARE列表从上到下 - 响应阶段: 从下到上
例如配置:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'myapp.middleware.RequestTimeMiddleware', # 第二个执行
'django.middleware.common.CommonMiddleware',
]
在这个例子中,RequestTimeMiddleware的process_request会在SecurityMiddleware之后执行,但它的process_response会在SecurityMiddleware之前执行。
六、实际应用场景
- 性能监控 - 记录请求耗时,慢请求报警
- 认证授权 - 统一处理JWT验证,权限检查
- 流量控制 - 实现API限流
- 数据预处理 - 请求数据清洗,格式化
- 响应处理 - 统一错误格式,添加标准头
下面是一个限流中间件的示例:
# 技术栈: Django 4.2
from django.core.cache import cache
from django.http import JsonResponse
class RateLimitMiddleware:
"""
API限流中间件
1. 基于IP的请求限流
2. 滑动窗口算法实现
3. 返回429状态码和剩余时间
"""
def __init__(self, get_response):
self.get_response = get_response
self.WINDOW_SIZE = 60 # 60秒窗口
self.MAX_REQUESTS = 100 # 最大100请求/分钟
def __call__(self, request):
ip = request.META.get('REMOTE_ADDR')
cache_key = f"ratelimit:{ip}"
# 获取当前请求计数
current = cache.get(cache_key, 0)
if current >= self.MAX_REQUESTS:
# 计算剩余时间
ttl = cache.ttl(cache_key)
return JsonResponse(
{'error': 'Too many requests', 'retry_after': ttl},
status=429
)
# 增加计数(如果key不存在,会自动创建)
cache.set(cache_key, current + 1, self.WINDOW_SIZE)
return self.get_response(request)
七、技术优缺点分析
优点:
- 代码复用 - 一处实现,全局生效
- 解耦 - 业务逻辑与横切关注点分离
- 灵活 - 可以随时启用/禁用中间件
- 性能 - 比在每个视图单独处理更高效
缺点:
- 调试困难 - 错误可能发生在中间件链的任何位置
- 顺序敏感 - 错误的顺序可能导致意外行为
- 全局影响 - 一个坏的中间件可能影响整个应用
八、注意事项
- 性能影响 - 中间件会增加请求处理时间,避免复杂逻辑
- 异常处理 - 妥善处理中间件中的异常,避免500错误
- 测试覆盖 - 中间件需要单独测试,模拟请求/响应对象
- 依赖顺序 - 确保中间件按正确顺序加载
- 禁用场景 - 某些管理命令不会加载中间件
九、总结
Django中间件是一个强大的工具,能够优雅地处理横跨整个应用的关注点。通过本文的示例,我们学习了如何创建各种实用的中间件。记住中间件的核心思想是"拦截-处理-传递",合理使用可以让代码更干净、更可维护。
在实际项目中,建议从简单需求开始,逐步构建更复杂的中间件。同时要注意中间件的执行顺序和性能影响,避免过度使用导致系统难以维护。
评论