中间件机制
问题
Python Web 框架中的中间件机制是什么?Django、Flask、FastAPI 的中间件有何不同?
答案
中间件是请求/响应处理管道中的一个环节,用于在视图函数前后执行通用逻辑(日志、认证、CORS 等)。
Django 中间件
Django 中间件遵循洋葱模型,请求从外到内,响应从内到外:
# Django 中间件(new-style)
class TimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 请求阶段(从外到内)
start = time.time()
response = self.get_response(request) # 调用下一层
# 响应阶段(从内到外)
duration = time.time() - start
response["X-Duration"] = f"{duration:.3f}s"
return response
settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware", # 最外层
"myapp.middleware.TimingMiddleware",
"django.middleware.common.CommonMiddleware", # 最内层
]
FastAPI / Starlette 中间件
基于 ASGI,原生异步:
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
token = request.headers.get("Authorization")
if not token and request.url.path != "/public":
return JSONResponse(status_code=401, content={"error": "Unauthorized"})
response = await call_next(request)
return response
app.add_middleware(AuthMiddleware)
Flask 中间件
Flask 使用装饰器钩子而非传统中间件类:
@app.before_request
def check_auth():
if request.endpoint != "public" and not request.headers.get("Authorization"):
return jsonify(error="Unauthorized"), 401
@app.after_request
def add_cors(response):
response.headers["Access-Control-Allow-Origin"] = "*"
return response
执行顺序对比
常见面试问题
Q1: 中间件和装饰器有什么区别?
答案:
| 维度 | 中间件 | 装饰器 |
|---|---|---|
| 作用范围 | 全局所有请求 | 单个视图函数 |
| 注册方式 | 配置文件/app 注册 | @decorator 语法 |
| 适用场景 | 日志、CORS、认证 | 权限检查、缓存 |
Q2: Django 中间件的 5 个钩子是什么?
答案:
process_request(request)— 请求到达视图前process_view(request, view_func, args, kwargs)— 视图调用前process_exception(request, exception)— 视图抛异常时process_template_response(request, response)— 模板响应时process_response(request, response)— 响应返回前
新版中间件用 __call__ 统一处理,但这些钩子方法仍然可用。
Q3: 如何实现一个 CORS 中间件?
答案:
class CORSMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
# 处理预检请求
if request.method == "OPTIONS":
response = Response()
else:
response = await call_next(request)
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
return response
实际项目中应使用框架提供的 CORS 中间件(如 fastapi.middleware.cors.CORSMiddleware),避免遗漏安全细节。