R / Richie全部文章 ↑

Python · 2 分钟阅读

中间件基础

中间件是"请求/响应"链路上的钩子函数,按 settings.MIDDLEWARE 顺序串成一条链。

5 个钩子

钩子 触发时机 用途
process_request 路由前 拦截、限流、注入
process_view 视图前 鉴权、注入上下文
process_response 视图后 改响应头、统一包装
process_exception 视图抛异常 统一异常处理
process_template_response 视图返回 TemplateResponse 渲染前最后修改

执行顺序

请求 → MW1.process_request → MW2.process_request → ... → MW2.process_view → MW1.process_view → View
响应 ← MW1.process_response ← MW2.process_response ← ... ← MW2.process_view(返回) ← MW1.process_view(返回)

总结:请求自上而下,响应自下而上。

快速上手

# core/middleware.py
import time

class TimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        start = time.perf_counter()
        response = self.get_response(request)
        duration = (time.perf_counter() - start) * 1000
        response["X-Request-Time-ms"] = f"{duration:.2f}"
        return response
# settings.py
MIDDLEWARE = [
    "core.middleware.TimingMiddleware",
    # ... 其它中间件
]

process_request 返回值

  • 返回 None — 继续往下走
  • 返回 HttpResponse — 立即返回,跳过后续中间件和视图
class IPBlockMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.blocked = {"1.2.3.4"}

    def __call__(self, request):
        ip = request.META.get("REMOTE_ADDR")
        if ip in self.blocked:
            from django.http import HttpResponseForbidden
            return HttpResponseForbidden("Blocked")
        return self.get_response(request)

现代写法(new-style)

Django 1.10+ 推荐的"可调用对象"写法简洁高效,99% 的场景无需再写 process_request / process_response 分开的方法。

注意事项

  • 中间件顺序敏感(特别是 SessionMiddleware 必须在 AuthenticationMiddleware 之前)
  • 不要在中间件里做"重活",会拖慢每次请求
  • 异步视图(async def view)请使用 async def __call__