Django 自定义中间件保姆级教程:从原理到实战(附源码)

中间件是Django项目开发中高频使用的核心组件 —— 它既能实现全局请求拦截,又能避免业务代码侵入,是 Django 灵活性的关键体现。本文会从原理拆解到实战开发,带大家彻底掌握自定义中间件,即使是新手也能跟着步骤落地。

一、先搞懂:中间件到底是什么?

中间件是 Django 提供的「轻量级插件系统」,它能介入 HTTP 请求从接收→处理→响应的全生命周期,在全局范围内对请求 / 响应做统一处理,且无需修改视图、路由等核心业务代码。

举个实际项目中的例子:
如果需要对所有接口做「Token 验证」,你不需要在每个视图函数里写一遍 Token 校验逻辑 —— 只需写一个 Token 中间件,就能让所有请求在到达视图前先经过验证,无效 Token 直接返回 401,有效 Token 才放行到视图。

二、核心原理:中间件的「双向流动」机制

理解中间件的关键,在于搞懂请求和响应的「流动顺序」。这里用一个实际项目的 MIDDLEWARE 配置举例(包含 Django 内置中间件和自定义中间件):

# settings.py
MIDDLEWARE = [
    # 内置中间件:安全相关处理(如 HTTPS 重定向)
    "django.middleware.security.SecurityMiddleware",
    # 内置中间件:会话管理(如 request.session)
    "django.contrib.sessions.middleware.SessionMiddleware",
    # 内置中间件:通用 HTTP 处理(如路径补全、反向解析)
    "django.middleware.common.CommonMiddleware",
    # 内置中间件:CSRF 防护
    "django.middleware.csrf.CsrfViewMiddleware",
    # 内置中间件:用户认证(如 request.user)
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    # 自定义中间件:Token 验证(我们自己写的)
    "myapp.middleware.TokenAuthMiddleware",
    # 自定义中间件:请求耗时统计(我们自己写的)
    "myapp.middleware.RequestTimeMiddleware",
]

基于这个配置,请求和响应的流动过程如下:

1. 请求阶段:「从上到下」的「放行链」

当客户端发送请求到 Django 服务器时,请求会按 MIDDLEWARE 列表的顺序,依次经过每个中间件,最终到达视图函数。

流程拆解:

客户端请求 → SecurityMiddleware → SessionMiddleware → CommonMiddleware → CsrfViewMiddleware → AuthenticationMiddleware → TokenAuthMiddleware → RequestTimeMiddleware → 视图函数

每个中间件在这个阶段的作用是「预处理请求」:

  • 比如 SessionMiddleware 会从 Cookie 中读取 SessionID,把对应的会话数据挂载到 request.session
  • 我们写的 TokenAuthMiddleware 会从请求头读取 Token,验证通过后才让请求继续往下走。

2. 响应阶段:「从下到上」的「加工链」

当视图函数处理完请求、返回响应后,响应会按 MIDDLEWARE 列表的逆序,再次经过每个中间件,最终返回给客户端。
流程拆解:

视图函数 → RequestTimeMiddleware → TokenAuthMiddleware → AuthenticationMiddleware → CsrfViewMiddleware → CommonMiddleware → SessionMiddleware → SecurityMiddleware → 客户端

每个中间件在这个阶段的作用是「后处理响应」:

  • 比如 RequestTimeMiddleware 会计算请求总耗时,把耗时信息添加到响应头;
  • SecurityMiddleware 会给响应添加 X-Content-Type-Options 等安全头,防止浏览器漏洞。

3. 关键:中间件的「双方法约定」

为什么中间件能实现这种「双向流动」?核心是 Django 对中间件类有两个强制约定(固定语法):

1、__init__    项目启动时(仅执行一次),用于初始化中间件,保存「下一个处理者」的引用。
2、__call__   每次请求到达时,处理请求(前半段)、处理响应(后半段)

用伪代码理解这两个方法的协作:

# my_middleware.py
class CustomMiddleware:
    def __init__(self, get_response):
        # 项目启动时执行1次:保存「下一个中间件/视图」的引用
        self.get_response = get_response
        print("中间件初始化完成(仅执行1次)")

    def __call__(self, request):
        # 1. 请求阶段:每次请求都会执行(从上到下)
        print("请求经过中间件:预处理请求")
        
        # 关键:调用「下一个处理者」(传递请求)
        response = self.get_response(request)
        
        # 2. 响应阶段:每次响应都会执行(从下到上)
        print("响应经过中间件:后处理响应")
        
        return response  # 返回处理后的响应

这里有个新手容易踩的坑:
__init__ 是项目启动时执行,不是请求到达时执行!如果在 __init__ 里写了「依赖请求的逻辑」(比如读取 request.META),会直接报错 —— 因为初始化时根本没有 request 对象。

三、实战:实现一个自定义中间件demo

前置准备:项目结构

初始化一个新的Django工程

set_middlewareProject/  # 项目根目录(终端显示的顶层目录)
├─ set_middlewareProject/  # 项目核心配置目录(与项目同名,关键!)
│  ├─ __pycache__/       # Python编译缓存目录(自动生成,无需修改)
│  ├─ __init__.py        # 空文件,标记该目录为Python包
│  ├─ asgi.py            # ASGI协议配置(部署用,暂不涉及)
│  ├─ settings.py        # 项目配置文件(需在这里注册中间件)
│  ├─ urls.py            # 项目URL路由配置
│  └─ wsgi.py            # WSGI协议配置(部署用,暂不涉及)
├─ templates/            # 模板文件目录(若用模板渲染,暂不涉及中间件)
├─ db.sqlite3            # Django默认SQLite数据库文件(自动生成)
└─ manage.py             # Django项目命令行工具(启动、创建应用等)

启动服务

步骤 1:编写中间件代码

新建一个.py文件设置自定义中间件:

# my_middleware.py
class CustomMiddleware:
    def __init__(self,get_response):
        self.get_response = get_response

    def __call__(self,request):
        # 在视图处理请求之前的逻辑
        print("在视图处理请求之前,中间件先对请求进行预处理")

        response = self.get_response(request)

        # 在视图处理请求之后的逻辑
        print("在视图处理请求之后,在响应发出去之前对响应进行操作")

        return response

注:自定义中间件需要按固定结构写:

class 中间件类名:
    def __init__(self, get_response):
        self.get_response = get_response  # 固定逻辑
        
    def __call__(self, request):
        # 处理请求(可选)
        response = self.get_response(request)  # 固定逻辑
        # 处理响应(可选)
        return response  # 固定逻辑

步骤 2:注册中间件

在 settings.py 的 MIDDLEWARE 列表中添加该中间件。

步骤 3:测试效果

启动服务,通过浏览器访问服务查看控制台响应结果:

请求处理过程:

请求 → SecurityMiddleware → SessionMiddleware → CommonMiddleware → ... →

你的自定义中间件 → 视图函数

响应处理过程:

视图函数 → 你的自定义中间件 → ... → CommonMiddleware → SessionMiddleware → SecurityMiddleware → 返回给客户端

回到自定义中间件文件添加更多处理逻辑:

# my_middleware.py
class CustomMiddleware:
    def __init__(self,get_response):
        self.get_response = get_response

    def __call__(self,request):
        # 在视图处理请求之前的逻辑
        print("在视图处理请求之前,中间件先对请求进行预处理")
        print(f'request.path: {request.path}')

        response = self.get_response(request)

        # 在视图处理请求之后的逻辑
        print("在视图处理请求之后,在响应发出去之前对响应进行操作")
        print(f'response.status_code: {response.status_code}')
        # 可以修改响应内容
        response.content = "<h1>这是中间件修改后的响应内容</h1>"
        return response

重新启动服务器查看响应结果:

此时可以看到控制台打印了我们新增的输出信息,并且在浏览器上显示的是我们在response返回前更改的内容。到这里,这个例子就完成了。

四、总结

中间件是 Django 生态中极具灵活性的组件,核心价值在于「全局统一处理,不侵入业务代码」。掌握它的关键是:

  1. 理解「请求从上到下、响应从下到上」的流动机制;
  2. 遵守 __init__ 和 __call__ 的固定语法;
  3. 实战中注意中间件顺序和白名单设计。

后续你可以基于本文的思路,扩展更多实用中间件:比如「IP 黑名单拦截」「请求参数日志打印」「响应数据压缩」等,进一步提升项目的可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值