← 返回题目列表

Django 中间件的作用是什么?执行顺序是怎样的?

高频 中等 第 8 / 27 题 更新于 2026/07/27
Django中间件请求响应横切逻辑

简化版

Django 中间件是包裹在视图外层的请求/响应处理链,适合做安全、Session、认证、CSRF、日志、异常处理等横切逻辑。请求进入时按 MIDDLEWARE 从上到下执行,响应返回时按相反方向执行。

详细版

中间件的典型作用:

  • 请求前处理:补充请求信息、认证、限流、日志打点;
  • 视图前后包装:统一异常处理、权限检查;
  • 响应后处理:设置 Cookie、安全 Header、压缩响应;
  • 全局能力:Session、CSRF、防点击劫持等。

一个简单中间件:

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

    def __call__(self, request):
        print("request in")
        response = self.get_response(request)
        print("response out")
        return response

MIDDLEWARE 顺序很关键。例如 AuthenticationMiddleware 依赖 SessionMiddleware,所以通常要放在它后面。面试中要强调:中间件适合处理通用横切逻辑,不适合承载具体业务流程。

完整版教学

一、中间件为什么存在

一个 Web 项目会有很多请求都需要共同处理:

  • 判断用户是否登录;
  • 读取或写入 Session;
  • 防 CSRF;
  • 设置安全响应头;
  • 记录访问日志;
  • 捕获异常并统一返回格式。

如果这些逻辑都写在每个视图里,会大量重复,还容易漏。中间件的价值就是把这些横切逻辑放到统一管道里。

二、中间件像洋葱模型

假设有三个中间件:

MIDDLEWARE = ["A", "B", "C"]

请求阶段顺序:

A → B → C → View

响应阶段顺序:

View → C → B → A

这像一层层包住视图。越靠前的中间件越外层,最早看到请求,也最晚看到响应。

三、新式中间件的基本写法

Django 当前常见中间件写法基于 get_response

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

    def __call__(self, request):
        import time
        start = time.time()
        response = self.get_response(request)
        response["X-Cost-Time"] = str(time.time() - start)
        return response

__init__ 在服务启动时执行,__call__ 在每次请求时执行。self.get_response(request) 会把请求交给链路里的下一个中间件或最终视图。

四、顺序错误会导致奇怪问题

中间件不是随便排的。几个常见依赖:

  • SessionMiddleware 要在 AuthenticationMiddleware 之前,因为认证需要 session;
  • CsrfViewMiddleware 要在需要保护表单请求的链路里生效;
  • SecurityMiddleware 通常放得比较靠前,用于处理安全相关响应头;
  • 自定义异常包装中间件放在哪里,会影响它能捕获哪些异常。

面试时可以举例:如果认证中间件先于 session 中间件执行,request.user 的计算就可能缺少 session 信息,认证逻辑会出问题。

五、中间件不适合做什么

不要把业务流程塞进中间件:

  • 不要在中间件里写订单创建逻辑;
  • 不要在中间件里根据几十种业务状态跳转;
  • 不要让中间件依赖具体页面的表单字段;
  • 不要为了省事把所有权限规则都写成一个巨大中间件。

业务逻辑最好放在视图、服务层、模型方法或权限组件里。中间件应该保持通用、可预测、低耦合。

六、常见内置中间件

Django 常用内置中间件包括:

  • SecurityMiddleware:安全相关处理;
  • SessionMiddleware:Session 支持;
  • CommonMiddleware:一些通用 URL 和响应处理;
  • CsrfViewMiddleware:CSRF 防护;
  • AuthenticationMiddleware:把用户信息挂到 request.user
  • MessageMiddleware:消息框架;
  • XFrameOptionsMiddleware:点击劫持防护。

了解这些中间件能帮助你解释 Django 为什么开箱即用地提供认证、安全和会话能力。

七、中间件顺序为什么特别重要

Django 中间件是有顺序语义的,不是简单注册一组插件。请求进入时按 MIDDLEWARE 从上到下执行,响应返回时从下到上执行,因此前面的中间件可以为后面的中间件和视图准备环境。典型例子是 AuthenticationMiddleware 依赖 SessionMiddleware,因为认证用户通常需要从 session 中读取用户 ID。

如果顺序错误,问题可能非常隐蔽。例如 CSRF 中间件位置不当,可能导致请求校验行为不符合预期;自定义异常处理中间件放错位置,可能捕获不到想要处理的异常;压缩响应的中间件如果在修改响应内容的中间件之前执行,也可能导致结果不符合预期。

面试时可以用“洋葱模型”解释:请求像从外往里穿过一层层中间件,响应像从里往外返回。越靠前的中间件越外层,越适合做安全、基础设施、全局拦截;越靠后的中间件越接近视图,适合依赖前面已经准备好的上下文。

八、自定义中间件的工程边界

自定义中间件适合处理横切关注点,例如请求 ID、访问日志、统一异常包装、简单限流、灰度标记、租户识别等。它不适合承载具体业务流程,比如“下单时校验优惠券”这种逻辑应该放在业务服务或视图层,而不是全局中间件。

写中间件时要注意三点。第一,尽量保持轻量,因为每个请求都会经过它。第二,不要吞掉异常后返回模糊响应,否则排查困难。第三,如果支持异步项目,要确认中间件是否兼容 sync/async,否则可能引入阻塞或适配开销。

一个成熟回答可以补充:中间件是全局链路能力,不是万能入口。只要逻辑只影响某个视图或某类业务,优先考虑装饰器、Mixin、权限类、服务层,而不是放到全局中间件里。

九、常见误区与追问

追问角度正确回答风险点
执行顺序请求从上到下,响应从下到上忽略依赖关系
适用职责横切逻辑和全局能力塞入具体业务流程
性能影响每个请求都会经过中间件过重拖慢全站
  • 误区:中间件顺序无所谓。 Session、认证、CSRF、安全 Header 等能力存在依赖和包裹关系,顺序错误会导致隐藏问题。
  • 误区:中间件适合写所有公共业务。 它适合横切关注点,不适合订单创建、优惠校验这类具体业务流程。
  • 误区:中间件只处理 response。 新式中间件通过 get_response 包裹后续链路,请求进入和响应返回两个方向都能参与。
  • 追问:为什么 AuthenticationMiddleware 要依赖 SessionMiddleware? 因为认证用户通常需要读取 session 中的用户标识,所以 session 能力要先准备好。
  • 追问:自定义中间件如何避免拖慢接口? 保持轻量,不做大量数据库查询或远程调用;必须做时要有缓存、超时和降级策略。
  • 追问:异步项目里的中间件要注意什么? 要确认中间件是否支持 async 链路,避免同步阻塞代码破坏 ASGI 的并发收益。

记忆钩子:中间件像包住 View 的管道,越外层越早看到请求、越晚看到响应;它管全局横切,不管具体业务细节。

十、加强记忆

Django 中间件是视图外层的请求/响应管道:请求进来从上到下,响应出去从下到上。它适合做认证、Session、CSRF、安全 Header、日志、异常这类横切逻辑;顺序很重要,业务流程不要乱塞进中间件。