• Django框架-中间件


    中间件

    1、什么是Django的中间件?

    定义:中间件是一个用来处理Django的请求和响应的框架级别的钩子,它是一个轻量、低级别的插件

    系统,用于在全局范围内改变Django的输入和输出,每个中间件组件都负责一些特定的功能。

    白话:中间件就是在视图函数执行前后做一些额外的操作,本质就是一个自定义的,类中定义几个方法,用来在全局范围内处理请求和响应,在特定的时间去执行这些方法。

    介于request与response处理之间的一道处理过程

    Django的中间件执行顺序按settings.py中MIDDLEWARE注册索引从小到大执行

    2、Django的默认的中间件

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

    主要实现:

    用户登录

    日志记录

    crsf:对所有的post请求做了一个验证,生成crst_token放在cookie中

    session

    权限管理

    注意:对于所有请求的批量做处理的时候用中间件,单独对某几个函数做处理的时候用装饰器

    3、定义5个方法

    process_request(self,request)
    process_view(self, request, view_func, view_args, view_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    process_response(self, request, response)

    4、方法的执行时间及执行顺序

    4.1、process_request

    1. 执行时间
        在视图函数之前执行
    2. 参数
        request 和视图中的request是同一个
    3. 返回值
        返回None
        返回response对象
            不执行后面中间的process_request方法和视图
            直接执行当前值中间件的process_response方法
    4. 执行顺序
        按照注册的顺序执行

    4.2、process_response

    1. 执行时间
        在视图函数之后执行
    2. request, response
        request 和视图中的request是同一个
        response 返回的response对象
    3. 返回值
        返回response对象
    4. 执行顺序
        按照注册的倒序执行

    4.3、process_view

    1. 执行时间
        在视图函数之前,process_request之后执行
    2. 参数
        view_func  将要执行的视图函数
        view_args  视图函数的可变长位置参数
        view_kwargs 视图函数的可变长关键字参数
    3. 返回值
        返回  None  正常执行
        返回  response对象   不执行后面的process_view和视图,直接执行所有中间件的process_response方法
    
    4.执行顺序
        按照注册的顺序执行

    4.4、process_exception(有条件触发:有错误才执行)

    1. 执行时间
        在视图函数之后,process_response之前执行
    2. 参数
        exception  错误对象
    3. 返回值
        返回  None  不对错误进行处理,交给下一个中间件进行处理
        返回  response对象  下一个中间的process_exception不执行,直接执行所有中间件的process_response方法
    4. 执行顺序
        按照注册的倒序执行

    4.5、process_template_response(条件触发:视图返回的response有render方法)

    1. 执行时间
        在视图函数之后,process_response之前执行
    2. 参数
    3. 返回值
        返回 response对象
    4. 执行顺序
        按照注册的倒序执行,执行完所有的process_template_response方法后执行response.render方法

    6、中间件执行流程图

    7、django请求的生命周期图

    8、自定义中间件步骤

    8.1、在应用app的根目录下创建一个文件夹midd_test,文件夹里创建一个py文件eg:midd.py
    8.2、在midd.py中导入模块:from django.utils.deprecation import MiddlewareMixin
    8.3、在midd.py中写类且必须继承MiddlewareMixin类,类里写几个方法
    8.4、在项目setting.py中的MIDDLEWARE模块加上自定义的中间件路劲,
    格式为:app_name.文件夹.py文件名.类名 eg: 'middlewares_app.midd_test.midd.Throttle',

    9、中间件的方式解决登录

    中间件版的登录验证需要依靠session,所以数据库种要有django_session表。

    urlls.py

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/$, views.login , name='login'),
        url(r'^index/$', views.index, name='index'),
        url(r'^home/$', views.home, name='home'),    
    ]
    View Code

    views.py

     1 from django.shortcuts import render, HttpResponse, redirect
     2 from app01 import models
     3 
     4 
     5 def index(request):
     6     return HttpResponse('this is index page')
     7 
     8 
     9 def home(request):
    10     return HttpResponse('this is home page')
    11 
    12 
    13 def login(request):
    14     if request.method == 'POST':
    15         user = request.POST.get('user', '')
    16         pwd = request.POST.get('pwd', '')
    17         check = models.UserInfo.object.filter(username=user, password=pwd)
    18         if check:
    19             # 设置session
    20             request.session['user'] = user
    21             # 获取跳转登录页面之前的url
    22             next_url = request.GET.get('next')
    23             # 如果有,就跳转回登陆之前的url,否则默认跳转到index页面
    24             if next_url:
    25                 return redirect(to=next_url)
    26             else:
    27                 # return redirect('/index/')
    28                 from django.shortcuts import reverse
    29                 return redirect(reverse(viewname=index))  # url反向解析
    30     return render(request, 'login.html')
    View Code

    login.html

     1 {% load static %}
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6 {#<link rel="icon" href="/static/Bootstrap/imags/logo.jpg"> 下面的方式是静态文件动态#}
     7     <link rel="icon" href="{% static 'Bootstrap/imags/logo.jpg' %}">
     8     <title>登陆页面</title>
     9 </head>
    10 <body>
    11 <form action="{% url 'login' %}">
    12     {% csrf_token %}
    13     <div>
    14         <label for="user">用户名:</label>
    15         <input type="text" id="user" name="user">
    16     </div>
    17     <div>
    18         <label for="pwd">用户名:</label>
    19         <input type="password" id="pwd" name="pwd">
    20     </div>
    21     <p><input type="submit" value="登录"></p>
    22 </form>
    23 </body>
    24 </html>
    View Code

    mymidd.py

     1 from django.utils.deprecation import MiddlewareMixin
     2 
     3 
     4 class AuthMd(MiddlewareMixin):
     5     white_list = ['/login/', ]   # 白名单
     6     black_list = ['/black/', ]   # 黑名单
     7 
     8     def  process_request(self,request):
     9         from django.shortcuts import redirect, HttpResponse
    10         
    11 
    12         next_url = request.path_info
    13         # 黑名单的网址限制访问
    14         if  next_url  in  self.black_list:
    15             return   HttpResponse('this is an illegal url')
    16         elif  next_url in self.white_list   or  request.session.get('user'):
    17             return None
    18         else:
    19             return redirect('/login/?next={}'.format(next_url))

    settings.py中注册自定义的中间件

     1 MIDDLEWARE = [
     2     'django.middleware.security.SecurityMiddleware',
     3     'django.contrib.sessions.middleware.SessionMiddleware',
     4     'django.middleware.common.CommonMiddleware',
     5     'django.middleware.csrf.CsrfViewMiddleware',
     6     'django.contrib.auth.middleware.AuthenticationMiddleware',
     7     'django.contrib.messages.middleware.MessageMiddleware',
     8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     9     'mymiddl.AuthMd'
    10 ]
    11 
    12 注册中间件
    View Code

    AuthMd中间件注册后,所有的请求都要走AuthMd的process_request方法。

    如果url在黑名单中,则返回this is an illegal url;

    访问的url在白名单内或者session中有urser用户名,则不做阻拦走正常流程,不需要登录就可以访问,如正常的注册,登录,主页;

    其它正常的url都是需要登录后访问,让浏览器跳转到登录页面。

    注:AuthMd中间件需要session,所以AuthMd注册的位置需要在session中间的下方。

    10、中间件的方式做分流控制

     1 # 存放用户数据
     2 visit_list = {
     3     # ip:[]  访问ip对应,每次访问时间
     4 
     5 
     6 
     7 class Throttle(MiddlewareMixin):
     8     """获取ip,记录时间,记录次数,根据访问记录做判断"""
     9 
    10     def process_request(self, request):
    11         print(request.META)
    12         ip = request.META.get('REMOTE_ADDR')  # 获取访问ip
    13         now = time.time()  # 记录当前时间,每次时间加入到最前面,即列表索引为0的位置
    14         if not visit_list.get(ip, ''):  # 首先判断当前访问ip是否在列表中
    15             visit_list[ip] = []  # 不在的话,将访问ip加入到字典中,并创建value为空列表
    16         # visit_list[ip].insert(0, now)
    17         # 在的话,比较访问时间是否在10秒内,就可以访问,故删除之前的时间,将当前的时间写入
    18         # 如果ip存在获取ip的访问时间记录列表
    19         history = visit_list[ip]
    20         print(history)
    21         temp_list = []  # 解决循环删除列表问题
    22         for i in history:
    23             if now - i > 10:  # 如果相距上次访问大于10秒,就将之前的清除[以防因记录3次导致符合要求的无法访问],将本次的时间写入
    24                 temp_list.append(i)  # 加入到临时列表
    25             else:
    26                 # 再如果ip存在且在10秒内再次访问,检查访问的次数
    27                 if len(history) >= 3:  # 就不需要再加入时间了,直接返回警告
    28                     return HttpResponse('访问频率太快了,请等10秒后再来访问')
    29         for j in temp_list:
    30             history.remove(j)
    31         history.insert(0, now)
    32 
    33 
    34 ------------------------------------------------------------------------------------
    35 class Throttle(MiddlewareMixin):
    36     """获取ip,记录时间,记录次数,根据访问记录做判断"""
    37 
    38     def process_request(self, request):
    39         ip = request.META.get('REMOTE_ADDR')
    40         now = time.time()
    41         if not visit_list.get(ip, ""):
    42             visit_list[ip] = []  # 添加新用户,创建key:vulue
    43             visit_list[ip].insert(0, now)  # 每次都添加到第一个位置
    44         else:
    45             if now - visit_list[ip][0] > 10:  # 超过10秒更新最新访问时间
    46                 visit_list[ip].clear()   # 清空列表
    47                 visit_list[ip].insert(0, now)
    48             else:  # 未超过10秒,再来检测已访问的次数
    49                 if len(visit_list[ip]) >= 3:
    50                     return HttpResponse('too fast ,waiting a moment')
    51                 else:
    52                     visit_list[ip].insert(0, now)   # 小于三次就把时间记录上
    53 
    54 --------------------------------------------------------------------------------------
    55 visit_list = {
    56     # 127.0.0.1:[]
    57 }
    58 
    59 class Throttle(MiddlewareMixin):
    60 
    61     def process_request(self, request):
    62         # 1.
    63         # 获取ip
    64         ip = request.META.get('REMOTE_ADDR')
    65 
    66         if not visit_list.get(ip, ''):
    67             visit_list[ip] = []
    68         history = visit_list[ip]
    69         now = time.time()
    70         # [ 10:21:10 ,10:21:06 ,10:21:05 ]
    71         # 2. 记录时间
    72         # 3. 根据访问记录做判断
    73         while history and now - history[-1]>5:
    74             history.pop()
    75 
    76         if len(history) >= 3:
    77             return HttpResponse('频率太快了')
    78         history.insert(0,now)
    未优化版
     1 -----midd.py    # 在自己创建的py文件中写如下类
     2 
     3 import time
     4 from django.utils.deprecation import MiddlewareMixin
     5 from django.shortcuts import HttpResponse
     6 
     7 """
     8 # 需求:限制访问频率&限制用户10秒内访问同一页面最多3次,防止重复请求,增加服务器压力
     9 思路:
    10 1、获取访问用户的ip
    11 2、记录每次用户访问该页面时的时间
    12 3、比较用户每次访问时与前一次访问时间,如果超过10秒,可以继续访问,记录时间,
    13 如果未超过,再看是否超过3次,如果超过次数,拒绝访问
    14 4、设计存放用户访问记录的格式:{ip:[time1,time2,time3]}
    15 5、每次过来通过ip获取上次的访问时间,做比较
    16 """
    17 
    18 # 存放用户数据
    19 visit_list = {
    20     # ip:[]  访问ip对应,每次访问时间
    21 }
    22 
    23 class Throttle(MiddlewareMixin):
    24     """获取ip,记录时间,记录次数,根据访问记录做判断"""
    25 
    26    def process_request(self, request):
    27         ip = request.META.get('REMOTE_ADDR')
    28         now = time.time()
    29         if not visit_list.get(ip, ""):
    30             visit_list[ip] = []  # 添加新用户,创建key:vulue
    31         else:
    32             if now - visit_list[ip][0] > 10:  # 超过10秒更新最新访问时间
    33                 visit_list[ip].clear()  # 清空列表
    34             else:  # 未超过10秒,再来检测已访问的次数
    35                 if len(visit_list[ip]) >= 3:
    36                     return HttpResponse('too fast ,waiting a moment')
    37         visit_list[ip].insert(0, now)  # 小于三次就把时间记录上 , 每次都添加到第一个位置
    上面的逻辑是错的,比如用户1,2,3秒时访问,属于10秒内3次访问,通过,第4秒时,小于10秒,但表中已经有3个了,不能访问,ok,
    但用户第11秒时访问,这时过来10秒,应该能访问,但虽然与最后一次时间比小于10秒,但列表中已经有了3个时间,就导致不能访问了,
    所以逻辑是错的,需要将最开始访问和现在时间比超过10秒的删除掉,保证列表中的时间永远是10秒内的。
  • 相关阅读:
    笔试助攻题(思路)
    const 修饰成员函数 前后用法(effective c++ 03)
    UNIX 是啥?!和Linux什么关系?
    我的offer之路(一)
    我的offer之路(一)
    ANSI C 与 K&R C
    c内置数据类型
    预处理器
    小数用二进制如何表示
    C++中有三种创建对象的方法
  • 原文地址:https://www.cnblogs.com/sunxiuwen/p/9677669.html
Copyright © 2020-2023  润新知