88.Django中间件的说明与使用方法

1. 概述

​ AOP(Aspect Oriented Programming ),面向切面编程,是对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。可以实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

​ 面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的,与主业务逻辑无关的代码,如安全检查,事物,日志等。若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使业务逻辑变得混杂不清。
举个例子:银行系统取款会有一个流程查询也会有一个流程。

在这里插入图片描述

​ Django的中间件,就是应用AOP技术来实现的,它是django请求/响应处理的钩子框架,是一个轻巧的低级“插件”系统,在不修改django项目原有代码的基础上,可以全局改变django的输入或输出,每个中间件组件负责执行某些特定功能。

​ PS:因为中间件改变的是全局(加入到整个流程),所以需要谨慎实用,滥用的话,会影响到服务器的性能。同样的,使用装饰器也可以达到这个效果,但是使用装饰器的话需要依次添加,代码会变得很复杂

2. django默认中间件

django项目默认有一些自带的中间件,如下:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

​ 一般情况下这些中间件都会启用(最少CommonMiddleware会启用)

3. 自定义中间件说明

如果需要增加自定义的中间件(该中间件类必须继承MiddlewareMixin(django.utils.deprecation)),一般是添加在系统的中间件之下,如:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
    # 自定义中间件
    'my_app.middleware.MyMiddleware',
]

中间件中主要有以下方法(一个中间件类最少需要实现下列方法中的一个):

  • process_request:处理请求对象,请求到达django框架时,第一时间调用

    多个中间件之间顺序调用

    参数:request

    返回:

    • response:调用当前中间件的process_response处理
    • None:调用下一个中间件的process_request处理
  • process_response:处理响应对象,视图函数返回response后,调用

    多个中间件之间倒序调用

    参数:request, response

    返回:

    • response:调用上一个中间件的process_response处理
  • process_view:视图预处理,在视图函数处理之前调用,即请求在urlconf当中匹配到对应的视图函数之后,先不调用视图函数,而是先调用此方法

    多个中间件之间顺序调用

    参数:request,view_func,view_args,view_kwargs

    ​ view_func:url路由匹配到的视图函数, 不是字符串,是函数对象

    ​ view_args:视图函数的可变参数

    ​ view_kwargs:视图函数的可变关键字参数

    返回:

    • response:调用最后一个中间件的process_response开始处理
    • None:调用下一个中间件的process_view处理
  • process_exception:在视图函数处理过程抛出异常时调用,中间件的方法(除了process_template_response)中抛出异常不会触发

    多个中间件之间倒序调用

    参数:request,exception

    ​ exception:是处理过程中抛出的异常对象

    返回:

    • response:之后的process_exception都不会触发,而是直接调用最后一个中间件的process_response处理
    • None:调用上一个中间件的process_exception处理
  • process_template_response:默认不执行,在视图函数完成操作后调用,除非视图函数返回的response中有render方法

    多个中间件之间倒序调用

    参数:request,response

    ​ response:不是HttpReponse,而是具有render方法的对象,譬如:SimpleTemplateResponse对象,在(django.template.response中)

    返回:

    • response:具有render方法的对象,继续调用上一个中间件的process_template_response处理,最后一个process_template_response处理完成后,会自动调用 response对象中的render方法,得到一个HttpResponse对象,进行返回,再调用process_response操作
    中间件方法的执行时有顺序的,process_request与process_view是按照顺序去执行的,而process_response、process_exception和process_template_response是反序的 :
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-io9SmTjf-1669197395429)(.\imgs\image-20210729085034649.png)]

​ 总结:用户请求 >> process_request >> urlconf路由匹配,找到对应的视图函数 >> process_view >> 视图函数 >> process_template_response(如果视图函数返回的response,有render方法,否则这一步不会执行) >> process_response >> 返回response到用户

​ 其中,在 视图函数 和 process_template_response 处理过程中,如果出现 exception ,那么就会倒序执行 中间件的process_exception

3.1 中间件调用顺序测试process_request

结果:
先执行中间件,按照settings配置顺序执行,然后再执行视图函数
urls

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('middleware_app.urls'))
]

views

from django.shortcuts import render,HttpResponse

# Create your views here.
def middleware_test(request):
    print('调用了视图函数')
    return HttpResponse('测试中间件成功')

中间件

from django.utils.deprecation import MiddlewareMixin
class FirstMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('FirstMiddleware process_request')

class SecondMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('SecondMiddleware process_request')

class ThirdMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('ThirdMiddleware process_request')

settings

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    # 自定义中间件
    'middleware_app.middlewaretest.FirstMiddleware',
    'middleware_app.middlewaretest.SecondMiddleware',
    'middleware_app.middlewaretest.ThirdMiddleware',

]

3.2 中间件调用顺序测试process_response

**结果: **
当request存在返回时。
返回顺序,先执行First然后,执行Second的request,然后渲染模板,最后从2执行到1的response。不执行3。
因为如果request存在返回时,执行完return就直接执行response,response又是倒叙执行,就跳过了3

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class FirstMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('FirstMiddleware process_request')
    def process_response(self,request,response):
        print('FirstMiddleware process_response')
        return response


class SecondMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('SecondMiddleware process_request')
        return HttpResponse('return SecondMiddleware')
    def process_response(self,request,response):
        print('SecondMiddleware process_response')
        return response


class ThirdMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('ThirdMiddleware process_request')
    def process_response(self,request,response):
        print('ThirdMiddleware process_response')
        return response

3.3 中间件调用顺序测试process_view

结果
如果不存在返回的话,就先执行request、view,再执行函数视图,再倒叙执行response。
如果存在返回的话,就先执行request,再顺序执行到存在返回的视图(不执行之后的),最后倒叙执行response。不执行函数视图了。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class FirstMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('FirstMiddleware process_request')
    def process_response(self,request,response):
        print('FirstMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('FirstMiddleware process_view')


class SecondMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('SecondMiddleware process_request')
        # return HttpResponse('return SecondMiddleware')
    def process_response(self,request,response):
        print('SecondMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('SecondMiddleware process_view')
        return HttpResponse('return SecondMiddleware')

class ThirdMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('ThirdMiddleware process_request')
    def process_response(self,request,response):
        print('ThirdMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('ThirdMiddleware process_view')

3.4 中间件调用顺序测试process_exception

结果
先将视图函数view中添加抛出异常代码。若exception无返回时,就按顺序执行request,顺序执行view。再倒叙执行exception。执行完views视图函数之后,倒叙执行response;
就按顺序执行request,顺序执行view。再倒叙执行exception,但是执行到返回函数就不会继续倒叙执行了。执行完views视图函数之后(但不会执行函数中raise抛出的异常),倒叙执行response。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class FirstMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('FirstMiddleware process_request')
    def process_response(self,request,response):
        print('FirstMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('FirstMiddleware process_view')
    def process_exception(self, request, exception):
        print('FirstMiddleware process_exception')


class SecondMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('SecondMiddleware process_request')
        # return HttpResponse('return SecondMiddleware')
    def process_response(self,request,response):
        print('SecondMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('SecondMiddleware process_view')
        # return HttpResponse('return SecondMiddleware')
    def process_exception(self, request, exception):
        print('SecondMiddleware process_exception')
        return HttpResponse('return SecondMiddleware')


class ThirdMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('ThirdMiddleware process_request')
    def process_response(self,request,response):
        print('ThirdMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('ThirdMiddleware process_view')
    def process_exception(self, request, exception):
        print('ThirdMiddleware process_exception')
from django.shortcuts import render,HttpResponse

# Create your views here.
def middleware_test(request):
    print('调用了视图函数')
    raise Exception('中间件抛出异常')
    return HttpResponse('测试中间件成功')

3.5 中间件测试调用顺序process_template_response

结果
若视图函数中不存在render,就不会触发process_template_response函数;若存在,在调用完视图后倒叙执行。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class FirstMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('FirstMiddleware process_request')
    def process_response(self,request,response):
        print('FirstMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('FirstMiddleware process_view')
    def process_exception(self, request, exception):
        print('FirstMiddleware process_exception')
    def process_template_response(self,request, response):
        print('FirstMiddleware process_template_response')
        return response


class SecondMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('SecondMiddleware process_request')
        # return HttpResponse('return SecondMiddleware')
    def process_response(self,request,response):
        print('SecondMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('SecondMiddleware process_view')
        # return HttpResponse('return SecondMiddleware')
    def process_exception(self, request, exception):
        print('SecondMiddleware process_exception')
        return HttpResponse('return SecondMiddleware')
    def process_template_response(self,request, response):
        print('SecondMiddleware process_template_response')
        return response


class ThirdMiddleware(MiddlewareMixin):
    def process_request(self,request):
        print('ThirdMiddleware process_request')
    def process_response(self,request,response):
        print('ThirdMiddleware process_response')
        return response
    def process_view(self,request,view_func,view_args,view_kwargs):
        print('ThirdMiddleware process_view')
    def process_exception(self, request, exception):
        print('ThirdMiddleware process_exception')
    def process_template_response(self,request, response):
        print('ThirdMiddleware process_template_response')
        return response

4. 常见自定义中间件功能

总之,你如果有对全局request或response的操作需求,那么就可以使用中间件,譬如:

  1. IP过滤:对一些特定IP地址返回特定响应
  2. URL过滤:如果用户访问的是login视图,则通过;如果访问其他视图,需要检测是不是有session已经有了就通过,没有就返回login页面。这样就不用在多个视图函数上写装饰器login_required
  3. 内容压缩:response内容实现gzip的压缩,返回压缩后的内容给前端
  4. CDN:内容分发网络,实现缓存,如果缓存中有数据直接返回,没有找到缓存再去请求视图
  5. URL过滤:某个子应用升级暂停使用,某个特定的path路径下的请求,返回一个特定页面

5. 使用中间件——示例URL过滤

如何使用Django中间件实现访问某一些网页进行跳转到指定URL的地址(登录,系统维护)
url

from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
    path('middleware_test/',views.middleware_test),
    path('middleware_url/', views.middleware_url)
]

views

from django.shortcuts import render,HttpResponse
from django.template.response import SimpleTemplateResponse
def middleware_url(request):
    return HttpResponse('系统功能升级中') # 不会访问到他

中间件views

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
from django.shortcuts import render
class URLMiddleware(MiddlewareMixin):
    def process_request(self,request):
        if request.path.startswith('/middleware_url/'):
            return render(request,'middleware_app/middleware_url.html')

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    系统在升级啊啊啊
</body>
</html>

settings配置

MIDDLEWARE = [
    # 最先触发
    'middleware_app.middlewaretest.URLMiddleware',

    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    # 自定义中间件
    'middleware_app.middlewaretest.FirstMiddleware',
    'middleware_app.middlewaretest.SecondMiddleware',
    'middleware_app.middlewaretest.ThirdMiddleware',

]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Django 2.2.2.dev20190508124537 文档 ========================== Django 文档 你所需要知道的关于 Django 的一切。 获取帮助 遇到问题?我们可以帮你! 试试 FAQ —— 这里有很多常见问题的解答。 正在寻找特定的信息?试试 索引,模块索引 或者 详细内容目录。 在 django-users 邮件列表的档案库搜索,或者 post a question。 在 #django IRC channel 频道提问 在我们的 ticket tracker 报告关于 Django 的 Bug。 这份文档是如何组织的 Django 有丰富的文档。一份高度概述的文档会告诉你在哪里找到特定的东西: 教程 通过手把手地方式教你一步步的创建一个 Web 应用。如果你初学 Django 或编程,请从这里开始。也请看看下面的 "快速入门"。 专题指南 在相当高的层次上介绍关键主题和概念,并提供有用的背景信息和解释。 参考指南 包含 API 和 Django 各个工作机制方面的技术参考。它们介绍了 Django 是如何工作,如何被使用的。不过,你得先对关键字的概念有一定理解。 操作指南 是一份目录。它们以排列好的关键问题和用例的方式指导你。它们比教程更加深入,且需要你先了解一些关于 Django 是如何工作的知识。 快速入门 您是刚学 Django 或是初学编程? 这就是你开始学习的地方! 从零开始: 概要 | 安装 入门教程: 第1节: 请求和响应 | 第2节: 模型和 admin 站点 | 第3节: 视图和模板 | 第4节: 表单和通用视图 | 第5节: 测试 | 第6节: 静态文件 | 第7节: 自定义 admin 站点 进阶教程 : 如何编写可复用的应用 | 提交你的第一个 Django 补丁 模型层 Django 提供了一个抽象的模型 ("models") 层,为了构建和操纵你的Web应用的数据。阅读下面内容了解更多: 模型: 模型介绍 | 字段类型 | 索引 | Meta 选项 | Model 类 QuerySet: 执行查询 | QuerySet 方法参考 | 查询表达式 Model 实例: 实例方法 | 访问关联的对象 迁移: 迁移概述 | 操作参考 | SchemaEditor | 编写迁移 高级: 管理员 | 原始 SQL | 事务 | 聚合 | 搜索 | 自定义字段 | 多个数据库 | 自定义查询 | 查询表达式 | 条件表达式 | 数据库函数 其它: 支持的数据库 | 旧数据库 | 提供初始化数据 | 优化数据库访问 | PostgreSQL 的特定功能 视图层 Django 具有 “视图” 的概念,负责处理用户的请求并返回响应。通过以下链接查找所有你需要知道的有关视图的信息: 基础: URL配置 | 视图函数 | 便捷工具 | 装饰器 参考: 内置视图 | Request/response 对象 | TemplateResponse 对象 文件上传: 概览 | 文件对象 | 存储 API | 管理文件 | 自定义存储 基于类的视图: 概览 | 内置显示视图 | 内置编辑视图 | 使用混入 | API 参考 | 扁平化索引 高级: 生成 CSV | 生成 PDF 中间件: 概览 | 内建的中间件类 模板层 模板层提供了一个对设计者友好的语法用于渲染向用户呈现的信息。学习如何使用语法(面向设计者)以及如何扩展(面向程序员): 基础: 概述 对于设计者: 语法概述 | 内建标签及过滤器(filters) | 人性化 针对程序员: 模板 API | 自定义标签(tags)和过滤器(filters) 表单 Django 提供了一个丰富的框架来帮助创建表单和处理表单数据。 基础: 概览 | 表单 API | 内建字段 | 内建 widgets 进阶: 针对模型的表单 | 整合媒体 | 表单集 | 自定义验证 开发进程 学习众多的组件及工具,来帮助你开发和测试 Django 应用: 设置: 概览 | 完整的设置列表 应用程序: 概览 异常: 概览 django-admin.py 和 manage.py: 概览 | 添加自定义命令 测试: 介绍 | 书写并运行测试 | 包含的测试工具 | 高级主题 部署: 概览 | WSGI 服务器 | 部署静态文件 | 用 email 跟踪代码错误 管理 找到所有你想知道的,关于自动化管理界面的知识,Django 最受欢迎的特性之一: 管理站点 管理动作 管理文档生成器 安全 在 Web 应用的发展中,安全是最重要主题,Django 提供了多种保护手段和机制。 安全概览 在 Django 中披露的安全问题 点击劫持保护

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想成为数据分析师的开发工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值