zoukankan      html  css  js  c++  java
  • 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秒内的。
  • 相关阅读:
    【题解】【BT】【Leetcode】Populating Next Right Pointers in Each Node
    【题解】【BT】【Leetcode】Binary Tree Level Order Traversal
    【题解】【BST】【Leetcode】Unique Binary Search Trees
    【题解】【矩阵】【回溯】【Leetcode】Rotate Image
    【题解】【排列组合】【素数】【Leetcode】Unique Paths
    【题解】【矩阵】【回溯】【Leetcode】Unique Paths II
    【题解】【BST】【Leetcode】Validate Binary Search Tree
    【题解】【BST】【Leetcode】Convert Sorted Array to Binary Search Tree
    第 10 章 判断用户是否登录
    第 8 章 动态管理资源结合自定义登录页面
  • 原文地址:https://www.cnblogs.com/sunxiuwen/p/9677669.html
Copyright © 2011-2022 走看看