django中间件以及自定义中间件

middleware

中间件就是在目标结果之间进行的额外处理过程,在Django中就是request和response之间进行的处理,相对来说实现起来比较简单,但是要注意它是对全局有效的,可以在全局范围内改变输入和输出结果,因此需要谨慎使用,否则不仅会造成难以定位的错误,而且可能会影响整体性能。

中间件有什么用

如果想要修改HttpRequest或者HttpResponse,就可以通过中间件来实现。

  • 登陆认证:在中间件中加入登陆认证,所有请求就自动拥有登陆认证,如果需要放开部分路由,只需要特殊处理就可以了。
  • 流量统计:可以针对一些渲染页面统计访问流量。
  • 恶意请求拦截:统计IP请求次数,可以进行频次限制或者封禁IP。

本身django项目就带有很多的中间件,在setting.py

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',
]

之前我们通过post请求发起的时候,就需要先注释掉csrf那一个中间件。

每个中间件的功能如下,

  • SecurityMiddleware:为request/response提供了几种安全改进;
  • SessionMiddleware:开启session会话支持;
  • CommonMiddleware:基于APPEND_SLASH和PREPEND_WWW的设置来重写URL,如果APPEND_SLASH设为True,并且初始URL 没有以斜线结尾以及在URLconf 中没找到对应定义,这时形成一个斜线结尾的新URL;
  • CsrfViewMiddleware:添加跨站点请求伪造的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值;
  • AuthenticationMiddleware:在视图函数执行前向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户,无它用不了request.user
  • MessageMiddleware:开启基于Cookie和会话的消息支持
  • XFrameOptionsMiddleware:对点击劫持的保护

除此以外, Django还提供了压缩网站内容的GZipMiddleware,根据用户请求语言返回不同内容的LocaleMiddleware和给GET请求附加条件的ConditionalGetMiddleware。这些中间件都是可选的。

Django的中间件执行顺序

当你在settings.py注册中间件时一定要要考虑中间件的执行顺序,中间件在request到达view之前是从上向下执行的,在view执行完后返回response过程中是从下向上执行的,如下图所示。举个例子,如果你自定义的中间件有依赖于request.user,那么你自定义的中间件一定要放在AuthenticationMiddleware的后面

image-20221102232915281

工作原理

HTTP Web服务器工作原理一般都是接收用户发来的请求(request), 然后给出响应(response)。Django也不例外,其一般工作方式是接收request对象和其它参数,交由视图(view)处理,然后给出它的响应(respone)数据: 渲染过的html文件或json格式的数据。然而在实际工作中Django并不是接收到request对象后,马上交给视图函数或类(view)处理,也不是在view执行后立马给用户返回reponse。事实上Django最初接收的是HttpRequest对象,而不是request对象,正是中间件的作用把HttpRequest对象和user对象打包成了一个全局变量request对象,这样你才可以View中使用request作为变量或者在模板中随意调用request.user。

image-20221102233759566

中间件(Middleware)在整个Django的request/response处理机制中的角色如下所示:

HttpRequest -> Middleware -> View -> Middleware -> HttpResponse

正是由于一个请求HttpRequest在传递给视图View处理前要经过中间件处理,经过View处理后的响应也要经过中间件处理才能返回给用户,我们可以编写自己的中间件实现权限校验,限制用户请求、打印日志、改变输出内容等多种应用场景,比如:

  • 禁止特定IP地址的用户或未登录的用户访问我们的View视图函数
  • 对同一IP地址单位时间内发送的请求数量做出限制
  • 在View视图函数执行前记录用户的IP地址
  • 在View视图函数执行前传递额外的变量或参数
  • 在View视图函数执行前或执行后把特定信息打印到log日志
  • 在View视图函数执行后对reponse数据进行修改后返回给用户

值得一提的是中间件对Django的输入或输出的改变是全局的,反之亦然。如果让你希望对Django的输入或输出做出全局性的改变时,需要使用中间件。举个例子,我们在装饰器一文中介绍了如何使用@login_required装饰器要求用户必须先登录才能访问我们的视图函数。试想我们有个网站绝大部分视图函数都需要用户登录,每个视图函数前面都需要加上@login_required装饰器是比较傻的行为。借助于中间件,我们无需使用装饰器即可全局实现:只有登录用户才能访问视图函数,匿名用户跳转到登录页面。实现原理也很简单,在一个request到达视图函数前,我们先对request.user是否验证通过进行判断,然后再进行跳转。另外Django对POST表单中携带的CSRF token的全局校验也是通过CsrfViewMiddleware这个中间件进行的,而不是通过单个装饰器实现的。

自定义中间件

image-20221102234020308

一般的中间件必须要有的两个函数就是process_requestprocess_response

如果自己定义中间件,首先在app里创建一个py文件,然后导入一些自带的模块

from django.utils.deprecation import MiddlewareMixin

然后就是自定义类

class ReginaMiddleWare(MiddlewareMixin):
    def process_request(self,request):
        '''

        :param request: 请求信息对象
        :return:
        '''
        print("reginaMiddleWare",request)
    def process_response(self,response,request):
        '''

        :param response: 请求信息对象
        :param request: 视图函数返回的响应体
        :return:
        '''
        print(response)
        return response

第三步就是把自己写好的中间件按照目录位置添加到settings文件当中

MIDDLEWARE = [
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'reginauser.reginaMiddleware.ReginaMiddleWare',
    'reginauser.reginaMiddleware.IvanleeMiddleWare'
]

image-20221103103835387

process_request功能

image-20221103002922820

ip = request.META.get("REMOTE_ADDR")
if ip in ['127.0.0.1','']:
  return HttpResponse("非法ip")

我们可以试一下本地地址,一旦process_request返回的不是默认的None,则表示拦截成功,那么也不会经过IvanleeMiddleware,直接回到ReginaMiddleware的响应处原路返回

image-20221103104006618image-20221103104042334

process_response

    def process_response(self,response,request):
        '''

        :param response: 请求信息对象
        :param request: 视图函数返回的响应体
        :return:
        '''
        print("ivanleeMiddleWare_response")
        response.content = response.content + b"<h1>I love Regina</h1>"  //必须是用b去定义转义类型
        return response

那么在返回的时候,响应内容就是原有的helloworld和IloveRegina一起发送给请求者。image-20221103104439201

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:django中间件以及自定义中间件 - Python技术站

(0)
上一篇 2023年4月2日
下一篇 2023年4月2日

相关文章

  • pip常见命令

    linux常用的一些命令笔记___pip3 [root@localhost ~]# pip3 –help Usage: pip3 <command> [options] Commands: install Install packages. download Download packages. uninstall Uninstall pack…

    2023年4月2日
    00
  • Django_渲染详解

    Django_render 模板语法 模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。 静态网页:页面上的数据都是写死的,万年不变 动态网页:页面上的数据是从后端动态获取的(比如后端获取当前时间;…

    2023年4月2日
    00
  • linux下c语言的crypt函数怎么用?

    linux的crypt 最近学校布置了一个网安的小作业,要用到linux里面的这个crypt函数,写一篇总结一下。首先我们要了解这个函数是用来做什么的。 密码影子文件中存储了每一个用户的用户明文和其单向哈希过的秘文 cipher = “$1$C68vnJ27$1ttFZ1/Rylq/xi350A0NI0”; 密码字段用\(id\)salt$hashed的格式…

    Linux 2023年4月17日
    00
  • django学习__1

    Django python网络编程回顾 之前我们介绍过web应用程序和http协议,简单了解过web开发的概念。Web应用程序的本质 接收并解析HTTP请求,获取具体的请求信息 处理本次HTTP请求,即完成本次请求的业务逻辑处理 构造并返回处理结果——HTTP响应 import socket server = socket.socket() server.b…

    Python开发 2023年4月2日
    00
  • django学习_路由

    django2 路由控制器 Route路由,是一种映射关系。路由是把客户端请求的url路径和用户请求的应用程序,这里意指django里面的视图进行绑定映射的一种关系。 请求路径和视图函数不是一一对应的关系 在django中所有的路由最终都被保存到一个叫urlpatterns的文件里,并且该文件必须在主应用下的urls.py里进行声明,这是由setting文件…

    2023年4月2日
    00
  • 爬虫学习1——request使用

    爬虫 什么是爬虫: – 通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程。 爬虫究竟是合法还是违法的? 在法律中是不被禁止 具有违法风险 善意爬虫 恶意爬虫 爬虫带来的风险可以体现在如下2方面:- 爬虫干扰了被访问网站的正常运营- 爬虫抓取了收到法律保护的特定类型的数据或信息 如何在使用编写爬虫的过程中避免进入局子的厄运呢? – 时常的优化自己…

    2023年3月31日
    00
  • matplotlib画图基础知识

    matplotlib plt.plot()绘制线性图 绘制单条线形图 绘制多条线形图 设置坐标系的比例plt.figure(figsize=(a,b)) 设置图例legend() 设置轴的标识 图例保存 fig = plt.figure() plt.plot(x,y) figure.savefig() import matplotlib.pyplot as …

    2023年4月2日
    00
  • linux文件权限解读

    Linux 文件权限 文件权限和文件类型共有10个字符组成,这10个字符可以分成三部分 \[d+rwx+rwx+rw-\\d:表示文件类型\\2-4位(第一组rwx):表示文件所有者的对文件的权限\\5-7位(第二组rwx):表示文件所有者所在组的用户对文件的权限\\8-10位(rw-):表示其他用户对文件的权限 \] 其中 r 表示可读,w 表示可写,x …

    Linux 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部