跳到主要内容

中间件机制

问题

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 个钩子是什么?

答案

  1. process_request(request) — 请求到达视图前
  2. process_view(request, view_func, args, kwargs) — 视图调用前
  3. process_exception(request, exception) — 视图抛异常时
  4. process_template_response(request, response) — 模板响应时
  5. 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),避免遗漏安全细节。

相关链接