zoukankan      html  css  js  c++  java
  • Django之中间件

    1、中间件是什么?

    中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

    2、做过什么?
      用户登录
      日志记录
      crsf:对所有的post请求做了一个验证
      session
      权限管理

    3、

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

      每一个中间件都有其对应的功能

    4、使用步骤:

     1 步骤:
     2 1、、先在创建的app下建一个文件夹,里面写一个py文件
     3 2、、然后开始写类
     4 1.中间件就是一个类,类里面写几个方法
     5 class M1(MiddlewareMixin):  必须继承
     6     def process_request(self,request):  request:请求里面的所有的东西
     7         print("m1.request_request") 
     8         这个方法里面别轻易返回值,要是有返回值就不再继续执行后面的了,执行自己的process_response和上边的response
     9         一般是无返回值的:继续执行后续的中间件和视图函数
    10     def process_response(self,request,response):
    11         return response
    12     
    13 2.在settings中的MIDDLEWARE加上路径    
    14     文件夹名称.py文件名称.类名
    15 3.找到继承的那个类,把那个类拿过来
    16   一般不要用导入的方法,不然有时候更新了就没有这个类了,你就把它继承的那个类拿过来,

    自定义中间件主要用到的几个方法(1、2、5比较常用)

    1   process_request(self,request)
    2 
    3     process_view(self, request, callback, callback_args, callback_kwargs)
    4 
    5     process_template_response(self,request,response)
    6 
    7     process_exception(self, request, exception)
    8 
    9     process_response(self, request, response)

    process_request和process_response

    当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

    上面的这些中间件都是Django自带的中间件,我们也可以自定义中间件。

    自定义中间件必须继承MiddlewareMixin

    定义的中间件本质其实就是一个类。

    自定义中间件的步骤如下:

    1.导入模块MiddlewareMixin

    from django.utils.deprecation import MiddlewareMixin

    2.自定义中间件

     1 from django.utils.deprecation import MiddlewareMixin
     2 from django.shortcuts import HttpResponse
     3 
     4 class Md1(MiddlewareMixin):
     5 
     6     def process_request(self,request):
     7         print("Md1请求")
     8  
     9     def process_response(self,request,response):
    10         print("Md1返回")
    11         return response
    12 
    13 class Md2(MiddlewareMixin):
    14 
    15     def process_request(self,request):
    16         print("Md2请求")
    17         #return HttpResponse("Md2中断")
    18     def process_response(self,request,response):
    19         print("Md2返回")
    20         return response

    3.在views里定义视图函数index

    def index(request):
    
        print("view函数...")
        return HttpResponse("OK")

    4.在settings.py的MIDDLEWARE里注册自己定义的中间件

    返回的结果:

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:

    返回Md2中断的页面,后台打印如下:

    Md1请求
    Md2请求
    Md2返回
    Md1返回

    流程图如下:

    总结:

    1. 中间件的process_request方法是在执行视图函数之前执行的。
    2. 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
    3. 不同中间件之间传递的request都是同一个对象

    多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

    process_view

    process_view(self, request, view_func, view_args, view_kwargs)

    该方法有四个参数

    request是HttpRequest对象。

    view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

    view_args是将传递给视图的位置参数的列表.

    view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

    Django会在调用视图函数之前调用process_view方法。

    它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

     1 from django.utils.deprecation import MiddlewareMixin
     2 from django.shortcuts import HttpResponse
     3 
     4 class Md1(MiddlewareMixin):
     5 
     6     def process_request(self,request):
     7         print("Md1请求")
     8         #return HttpResponse("Md1中断")
     9     def process_response(self,request,response):
    10         print("Md1返回")
    11         return response
    12 
    13     def process_view(self, request, callback, callback_args, callback_kwargs):
    14         print("Md1view")
    15 
    16 class Md2(MiddlewareMixin):
    17 
    18     def process_request(self,request):
    19         print("Md2请求")
    20         return HttpResponse("Md2中断")
    21     def process_response(self,request,response):
    22         print("Md2返回")
    23         return response
    24 
    25     def process_view(self, request, callback, callback_args, callback_kwargs):
    26         print("Md2view")

    执行结果如下:

    Md1请求
    Md2请求
    Md1view
    Md2view
    view函数...
    Md2返回
    Md1返回

    过程如下

    process_view可以调用视图函数

     1 class Md1(MiddlewareMixin):
     2 
     3     def process_request(self,request):
     4         print("Md1请求")
     5         #return HttpResponse("Md1中断")
     6     def process_response(self,request,response):
     7         print("Md1返回")
     8         return response
     9 
    10     def process_view(self, request, callback, callback_args, callback_kwargs):
    11 
    12         # return HttpResponse("hello")
    13 
    14         response=callback(request,*callback_args,**callback_kwargs)
    15         return response

    执行结果如下

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。

    process_exception

    process_exception(self, request, exception)

    该方法两个参数:

    一个HttpRequest对象

    一个exception是视图函数异常产生的Exception对象。

    这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

     1 class Md1(MiddlewareMixin):
     2 
     3     def process_request(self,request):
     4         print("Md1请求")
     5         #return HttpResponse("Md1中断")
     6     def process_response(self,request,response):
     7         print("Md1返回")
     8         return response
     9 
    10     def process_view(self, request, callback, callback_args, callback_kwargs):
    11 
    12         # return HttpResponse("hello")
    13 
    14         # response=callback(request,*callback_args,**callback_kwargs)
    15         # return response
    16         print("md1 process_view...")
    17 
    18     def process_exception(self,request,exception):
    19         print("md1 process_exception...")
    20 
    21 
    22 
    23 class Md2(MiddlewareMixin):
    24 
    25     def process_request(self,request):
    26         print("Md2请求")
    27         # return HttpResponse("Md2中断")
    28     def process_response(self,request,response):
    29         print("Md2返回")
    30         return response
    31     def process_view(self, request, callback, callback_args, callback_kwargs):
    32         print("md2 process_view...")
    33 
    34     def process_exception(self,request,exception):
    35         print("md1 process_exception...")

    没有错误执行结果如下:

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    
    Md2返回
    Md1返回

    对第二个process_exception做出如下修改

    def process_exception(self,request,exception):
    
            print("md2 process_exception...")
            return HttpResponse("error")

    执行结果如下===》视图函数出错执行这个process_view就会直接执行process_response。。

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    md2 process_exception...
    Md2返回
    Md1返回

    当视图函数出现错误,流程图如下:

    process_template_response(self,request,response)

    该方法对视图函数返回值有要求,必须是一个含有render方法类的对象,才会执行此方法

     1 class Test:
     2     def __init__(self,status,msg):
     3         self.status=status
     4         self.msg=msg
     5     def render(self):
     6         import json
     7         dic={'status':self.status,'msg':self.msg}
     8 
     9         return HttpResponse(json.dumps(dic))
    10 def index(response):
    11     return Test(True,'测试')

    四 中间件应用场景

    1、做IP访问频率限制

    某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。

    2、URL访问过滤

    如果用户访问的是login视图(放过)

    如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!

    CSRF跨站伪造攻击==》见下方博客,写的非常好

    https://www.cnblogs.com/liuqingzheng/p/9505044.html

    在form表单中应用:

    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>

    在Ajax中应用:

    放在data里:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <script src="/static/jquery-3.3.1.js"></script>
     6     <title>Title</title>
     7 </head>
     8 <body>
     9 <form action="" method="post">
    10     {% csrf_token %}
    11     <p>用户名:<input type="text" name="name"></p>
    12     <p>密码:<input type="text" name="password" id="pwd"></p>
    13     <p><input type="submit"></p>
    14 </form>
    15 <button class="btn">点我</button>
    16 </body>
    17 <script>
    18     $(".btn").click(function () {
    19         $.ajax({
    20             url: '',
    21             type: 'post',
    22             data: {
    23                 'name': $('[name="name"]').val(),
    24                 'password': $("#pwd").val(),
    25                 'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
    26             },
    27             success: function (data) {
    28                 console.log(data)
    29             }
    30 
    31         })
    32     })
    33 </script>
    34 </html>

    放在cookie里:

    获取cookie:document.cookie

    是一个字符串,可以自己用js切割,也可以用jquery的插件

    获取cookie:$.cookie('csrftoken')

    设置cookie:$.cookie('key','value')

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <script src="/static/jquery-3.3.1.js"></script>
     6     <script src="/static/jquery.cookie.js"></script>
     7     <title>Title</title>
     8 </head>
     9 <body>
    10 <form action="" method="post">
    11     {% csrf_token %}
    12     <p>用户名:<input type="text" name="name"></p>
    13     <p>密码:<input type="text" name="password" id="pwd"></p>
    14     <p><input type="submit"></p>
    15 </form>
    16 <button class="btn">点我</button>
    17 </body>
    18 <script>
    19     $(".btn").click(function () {
    20         var token=$.cookie('csrftoken')
    21         //var token='{{ csrf_token }}'
    22         $.ajax({
    23             url: '',
    24             headers:{'X-CSRFToken':token},
    25             type: 'post',
    26             data: {
    27                 'name': $('[name="name"]').val(),
    28                 'password': $("#pwd").val(),
    29             },
    30             success: function (data) {
    31                 console.log(data)
    32             }
    33 
    34         })
    35     })
    36 </script>
    37 </html>
    38 
    39 放在cookie里

    其它操作

    全站禁用:注释掉中间件 'django.middleware.csrf.CsrfViewMiddleware',

    局部禁用:用装饰器(在FBV中使用)

     1 from django.views.decorators.csrf import csrf_exempt,csrf_protect
     2 # 不再检测,局部禁用(前提是全站使用)
     3 # @csrf_exempt
     4 # 检测,局部使用(前提是全站禁用)
     5 # @csrf_protect
     6 def csrf_token(request):
     7     if request.method=='POST':
     8         print(request.POST)
     9 
    10         return HttpResponse('ok')
    11     return render(request,'csrf_token.html')

    在CBV中使用

     1 # CBV中使用
     2 from django.views import View
     3 from django.views.decorators.csrf import csrf_exempt,csrf_protect
     4 from django.utils.decorators import method_decorator
     5 # CBV的csrf装饰器,只能加载类上(django的bug)
     6 # 给get方法使用csrf_token检测
     7 @method_decorator(csrf_exempt,name='get')
     8 # 给post加
     9 @method_decorator(csrf_exempt,name='post')
    10 # 给所有方法加
    11 @method_decorator(csrf_exempt,name='get')
    12 class Foo(View):
    13     def get(self,request):
    14         pass
    15     def post(self,request):
    16         pass
  • 相关阅读:
    js 跳转链接
    reg.test is not a function 报错
    html中button自动提交表单?
    mysql主从复制及双主复制
    nginx反向代理后端web服务器记录客户端ip地址
    mysql多实例-主从复制安装
    LVS+Keepalived高可用负载均衡集群架构实验-01
    debug调试
    常用网站总结
    项目部署
  • 原文地址:https://www.cnblogs.com/Roc-Atlantis/p/9665039.html
Copyright © 2011-2022 走看看