Django中间件是一种在请求和响应处理过程中介入的机制,允许你在视图处理请求之前或之后执行自定义代码。中间件适用于处理全局性任务,如身份验证、日志记录、内容修改等。以下是Django中间件的详细说明和使用方法:
一、中间件的核心概念
-
作用阶段 :
• 请求阶段 :在路由到视图之前处理请求(如身份验证)。
• 视图阶段 :在调用视图前后执行操作(如权限检查)。
• 响应阶段 :在返回响应前修改内容(如添加HTTP头)。
• 异常阶段:处理视图或中间件抛出的异常(如统一错误处理)。
-
中间件类方法 :
•
process_request(request)
: 在路由到视图前调用。•
process_view(request, view_func, view_args, view_kwargs)
: 在视图被调用前执行。•
process_response(request, response)
: 在所有响应返回前处理。•
process_exception(request, exception)
: 处理视图抛出的异常。•
process_template_response(request, response)
: 处理模板响应(如修改上下文)。
二、创建自定义中间件
1. 编写中间件类
python
# myapp/middleware/custom_middleware.py
import logging
from django.http import HttpResponseForbidden
logger = logging.getLogger(__name__)
class SimpleLoggingMiddleware:
"""记录请求日志的中间件"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 请求处理前
logger.info(f"Request started: {request.method} {request.path}")
response = self.get_response(request) # 继续处理链
# 响应处理后
logger.info(f"Request finished: {request.method} {request.path} → {response.status_code}")
return response
class IPFilterMiddleware:
"""过滤非法IP的中间件"""
def __init__(self, get_response):
self.get_response = get_response
self.allowed_ips = ['127.0.0.1', '192.168.1.0/24'] # 允许的IP或网段
def __call__(self, request):
client_ip = request.META.get('REMOTE_ADDR')
if not self._is_ip_allowed(client_ip):
return HttpResponseForbidden("IP地址被禁止访问")
return self.get_response(request)
def _is_ip_allowed(self, ip):
# 简单示例:实际可能需要更复杂的IP检查逻辑
return ip in self.allowed_ips
2. 配置中间件
在 settings.py
的 MIDDLEWARE
列表中注册中间件:
python
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'myapp.middleware.custom_middleware.SimpleLoggingMiddleware', # 自定义中间件
'myapp.middleware.custom_middleware.IPFilterMiddleware', # 另一个中间件
]
执行顺序 :
• 中间件按列表顺序从上到下处理请求(process_request
)。
• 响应阶段按从下到上的顺序处理(process_response
)。
三、中间件的常见应用场景
1. 请求日志记录
记录每个请求的路径、方法、耗时等信息:
python
class RequestTimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start_time = time.time()
response = self.get_response(request)
duration = time.time() - start_time
print(f"Request to {request.path} took {duration:.2f} seconds")
return response
2. 用户认证增强
检查特定Header或Token:
python
class APITokenMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not request.user.is_authenticated:
token = request.headers.get('Authorization', '').split('Bearer ')[-1]
if token == 'SECRET_API_KEY':
# 模拟用户登录(示例逻辑)
request.user = get_user_model().objects.get(username='api_user')
return self.get_response(request)
3. 跨域请求处理(CORS)
手动添加CORS头(或使用第三方库如 django-cors-headers
):
python
class CustomCorsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response['Access-Control-Allow-Headers'] = 'Content-Type'
return response
4. 响应内容修改
压缩响应或替换敏感信息:
python
import gzip
class GzipResponseMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if 'gzip' in request.headers.get('Accept-Encoding', ''):
response.content = gzip.compress(response.content)
response['Content-Encoding'] = 'gzip'
return response
四、中间件的注意事项
-
性能影响 :
• 避免在中间件中执行耗时操作(如数据库查询),否则会拖慢所有请求。
• 使用缓存优化频繁访问的数据(如用户权限信息)。
-
异常处理 :
• 在
process_exception
中捕获异常时,需返回None
以继续传递异常。• 生产环境中应记录错误日志而非暴露堆栈信息。
-
中间件顺序 :
• 安全中间件(如
SecurityMiddleware
)通常应放在最前面。• 依赖其他中间件的组件(如
SessionMiddleware
需在认证中间件之前)。 -
测试中间件 :
• 使用Django测试客户端模拟请求,验证中间件行为:
pythonfrom django.test import RequestFactory, TestCase class TestMiddleware(TestCase): def test_ip_filter(self): factory = RequestFactory() request = factory.get('/', REMOTE_ADDR='192.168.1.5') middleware = IPFilterMiddleware(lambda r: None) response = middleware(request) self.assertEqual(response.status_code, 403) # 假设该IP被禁止
五、中间件与其他组件的对比
组件 | 用途 | 作用范围 |
---|---|---|
中间件 | 全局请求/响应处理(如日志、认证) | 所有HTTP请求 |
信号(Signal) | 响应特定事件(如保存模型后触发操作) | 应用内部事件 |
上下文处理器 | 向模板添加全局变量(如当前用户) | 模板渲染阶段 |
六、总结
Django中间件是处理HTTP请求和响应流程的核心机制,适用于以下场景:
• 全局功能 :如日志、IP过滤、性能监控。
• 请求预处理 :用户认证、数据解析。
• 响应后处理 :修改响应头、压缩内容。
• 异常统一处理:记录错误、返回友好提示。
通过合理设计中间件,可以解耦代码并增强应用的可维护性。但需谨慎设计以避免性能瓶颈和逻辑混乱。