zoukankan      html  css  js  c++  java
  • 第十五章 Django框架——中间件组件

    第十五章 Django框架——中间件组件

    一、中间件介绍

    二、自定义中间件

    三、应用场景

    四、csrf-token请求伪造

    五、禁用中间件的方法

     

    一、中间件介绍

    什么是中间件(what):

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

    中间件的作用(how):

    如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

    可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

    Django默认的中间件:(在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图)

    每一个中间件都有自己的功能

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

    二、自定义中间件

     中间件方法:

    process_request(self,request)
    process_view(self, request, callback, callback_args,callback_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    process_response(self, request, response)

    1.process_request和process_response

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

    请求顺序与响应顺序(请求是从上往下,响应是从下往上)

    操作步骤:

    ①导入模块

    from django.utils.deprecation import MiddlewareMixin

    ②自定义中间件

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
     
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            #return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response

    ③在view中定义一个视图函数(index)

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

    ④在settings.py里注册自定义组件

    结果:

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

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

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

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

    执行顺序如图:

    总结:

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

    2.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并返回结果。

    process_view(self, request, callback, callback_args, callback_kwargs)
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md1view")
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md2view")

    结果:

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

    执行顺序如下:

     

    当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。

    process_view可以用来调用视图函数:

    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
    
            # return HttpResponse("hello")
    
            response=callback(request,*callback_args,**callback_kwargs)
            return response

    结果:

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

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

    3.process_exception

    process_exception(self, request, exception)

    该方法两个参数:

    一个HttpRequest对象

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

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

    process_exception(self, request, exception)

    示例:

    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
    
            # return HttpResponse("hello")
    
            # response=callback(request,*callback_args,**callback_kwargs)
            # return response
            print("md1 process_view...")
    
        def process_exception(self,request,exception):
            print("md1 process_exception...")
    
    
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            # return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("md2 process_view...")
    
        def process_exception(self,request,exception):
            print("md1 process_exception...")
    View Code

    结果:

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

    执行顺序如下:

     将md2的process_exception修改如下:

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

    结果:

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

    4.process_template_response(self,request,response)

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

    class Test:
        def __init__(self,status,msg):
            self.status=status
            self.msg=msg
        def render(self):
            import json
            dic={'status':self.status,'msg':self.msg}
    
            return HttpResponse(json.dumps(dic))
    def index(response):
        return Test(True,'测试')
    View Code

    三、应用场景(转自https://www.cnblogs.com/liuqingzheng/articles/9509739.html)

    1.做IP访问频率限制

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

    2.URL访问过滤

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

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

    四、csrf-token请求伪造

    最简单的应用:form表单内添加{%csrf_token%}

    <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里一起传到后端):

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <script src="/static/jquery-3.3.1.js"></script>
        <title>Title</title>
    </head>
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="text" name="password" id="pwd"></p>
        <p><input type="submit"></p>
    </form>
    <button class="btn">点我</button>
    </body>
    <script>
        $(".btn").click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {
                    'name': $('[name="name"]').val(),
                    'password': $("#pwd").val(),
                    'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
                },
                success: function (data) {
                    console.log(data)
                }
    
            })
        })
    </script>
    </html>

    Cookie中的应用:

    获取cookie:document.cookie

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

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

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

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <script src="/static/jquery-3.3.1.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <title>Title</title>
    </head>
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="text" name="password" id="pwd"></p>
        <p><input type="submit"></p>
    </form>
    <button class="btn">点我</button>
    </body>
    <script>
        $(".btn").click(function () {
            var token=$.cookie('csrftoken')
            //var token='{{ csrf_token }}'
            $.ajax({
                url: '',
                headers:{'X-CSRFToken':token},
                type: 'post',
                data: {
                    'name': $('[name="name"]').val(),
                    'password': $("#pwd").val(),
                },
                success: function (data) {
                    console.log(data)
                }
    
            })
        })
    </script>
    </html>
    
    放在cookie里
    View Code

    五、禁用中间件的方法

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

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

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    # 不再检测,局部禁用(前提是全站使用)
    # @csrf_exempt
    # 检测,局部使用(前提是全站禁用)
    # @csrf_protect
    def csrf_token(request):
        if request.method=='POST':
            print(request.POST)
    
            return HttpResponse('ok')
        return render(request,'csrf_token.html')

    在CBV中使用:

    # CBV中使用
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    from django.utils.decorators import method_decorator
    # CBV的csrf装饰器,只能加载类上(django的bug)
    # 给get方法使用csrf_token检测
    @method_decorator(csrf_exempt,name='get')
    # 给post加
    @method_decorator(csrf_exempt,name='post')
    # 给所有方法加
    @method_decorator(csrf_exempt,name='get')
    class Foo(View):
        def get(self,request):
            pass
        def post(self,request):
            pass
  • 相关阅读:
    rest framework 认证 权限 频率
    rest framework 视图,路由
    rest framework 序列化
    10.3 Vue 路由系统
    10.4 Vue 父子传值
    10.2 Vue 环境安装
    10.1 ES6 的新增特性以及简单语法
    Django 跨域请求处理
    20190827 On Java8 第十四章 流式编程
    20190825 On Java8 第十三章 函数式编程
  • 原文地址:https://www.cnblogs.com/neymargoal/p/9664298.html
Copyright © 2011-2022 走看看