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

    一、中间件简介

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

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

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

    二、自定义中间件

    自定义步骤:

    1 写一个类,继承MiddlewareMixin
    from django.utils.deprecation import MiddlewareMixin
    
    2 里面写方法,至少写一个process_request(请求来了,一定会触发它的执行)
    def process_request(self, request):
        pass
    
    3 在setting中配置(注意,放在前和放在后)
        	MIDDLEWARE = [
                ...
        		'app01.mymiddle.MyMiddleware1',
                ...
    		]
    

    中间件执行顺序:

    请求来的时候从上往下执行
    请求走的时候,从下往上执行
    # 其实本质就是起了一个for循环,根据这个列表的索引一次执行
    

    所以我们可以在自定义中间件中写着两个方法达到自己的全局控制

    正因为这个执行顺序,所以自定义的中间件语句放的位置也就需要注意。比如我们的自定义中间件想要在请求来的时候对session先进行处理,那么我们就需要把中间件放在session的中间件后面,因为如果在它的前面根本就无法从request.session里取出值来。

    三、中间件的方法

    1.需要知道的方法

    多个中间件的方法执行顺序

    请求来的时候,从上往下执行各个中间件的process_request
    请求走的时候,从下往上执行各个中间件的process_response
    
    重点掌握:
    1 process_request(request对象)
    2 process_response(request对象,response对象)
    3 process_view
    4 process_exception
    了解:知道还有一个就行了,不需要记住
    process_template_response(self,request,response)
    该方法对视图函数返回值有要求,必须是一个含有render方法类的对象,才会执行此方法
    
            
    process_request可以干什么?
    	-写一个中间件,不管前端用什么编码,在requset.data中都有post的数据
        -频率限制(限制某个ip地址,一分钟只能访问5次)
        -登录认证(只要没登录,重定向到login路径)、
        -记录用户访问日志(ip,时间,访问路径)
        
    process_response可以干什么?内部有response对象
    	-统一给所有(某几个路径)加cookie
        -统一给所有(某几个路径)加响应头
        
        
        
    process_view 路由匹配成功和视图函数执行之前执行(callback就是视图函数)
        def process_view(self, request, callback, callback_args, callback_kwargs):
                # callback就是views视图函数
                # callback_args,无名分组的参数
                # callback_kwargs,有名分组的参数
                # 可以在这里面改变视图函数触发的时机,且可以在视图函数前后加代码,实现一个装饰器的功能
                res=callback(request)
                print("中间件的process_view")
                return res
    
    process_exception 视图函数出错,会执行它(全局异常捕获)(记录日志,哪个ip地址,访问哪个路径,出的错)
        # 全局异常捕获
        def process_exception(self, request, exception):
            print(exception)
            return render(request,'error.html')
    

    2.request与response流程图

    不是所有的请求都一定会走到视图函数,如下例子

    # 自定义中间件
    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
        
    # 视图函数
    def index(request):
        print("view函数...")
        return HttpResponse("OK")
    

    正常执行流程

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

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

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

    1

    由此总结一下:

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

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

    3.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方法。利用process_view方法可以改变视图函数的执行顺序。

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

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

    2

    4.process_exception执行流程

    process_exception(self, request, exception)

    该方法两个参数:

    一个HttpRequest对象

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

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

    4132

    四、CSRF_TOKEN跨站请求伪造

    csrf攻击:https://blog.csdn.net/xiaoxinshuaiga/article/details/80766369

    csrf攻击django是怎么预防的,从我们的网站发出的post请求都要带一个csrf为key,随机字符串为value的隐藏标签,如果有这个标签就可以进行提交,如果没有的话就禁止访问。

    django已经帮助我们集结了csrf攻击,是中间件django.middleware.csrf.CsrfViewMiddleware解决的

    1.在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()
                    'csrfmiddlewaretoken':'{{ csrf_token }}' 也行 
                },
                success: function (data) {
                    console.log(data)
                }
    
            })
        })
    </script>
    </html>
    

    2.在Ajax-cookie中的应用

    要导包jquery.cookie.js
    获取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里
    

    3.使用总结

        -form表单提交 
        	-在form表单中 {% csrf_token%}
            
        -ajax提交(需要自己把csrf串写进去)
        方式一:放到data中
         $.ajax({
                url: '/csrf_test/',
                method: 'post',
                data: {'name': $('[name="name"]').val(),
                    'password': $('[name="password"]').val(),
                    'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
                },
                success: function (data) {
                    console.log('成功了')
                    console.log(data)
    
                },
                error: function (data) {
                    console.log('xxxxx')
                    console.log(data)
    
                }
            })
            方式二:放到data中
            'csrfmiddlewaretoken':'{{ csrf_token }}'
            方式三:放到头中
            headers:{'X-CSRFToken':'{{csrf_token}}'},
    

    4.全局启用/禁用,局部禁用/启用

    使用django内置的装饰器

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    # 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有csrf校验了)
    @csrf_exempt
    def csrf_test(request):
        if request.method=='GET':
            return render(request,'csrf_test.html')
        else:
            name=request.POST.get('name')
            password=request.POST.get('password')
            print(name)
            print(password)
            return HttpResponse('登录成功')
    
    # 全局禁用,局部使用csrf(中间件注释,但这个视图还是需要csrf校验)
    @csrf_protect
    def csrf_test(request):
        if request.method=='GET':
            return render(request,'csrf_test.html')
        else:
            name=request.POST.get('name')
            password=request.POST.get('password')
            print(name)
            print(password)
            return HttpResponse('登录成功')
    
    
    
    # 高级(装逼)的使用方式,在urls.py中
    path('csrf_test/', csrf_exempt(views.csrf_test))
    
  • 相关阅读:
    PAT (Advanced Level) Practice 1129 Recommendation System (标记+排序)
    PAT (Advanced Level) Practice 1135 Is It A Red-Black Tree (30分) (红黑树知识+建树+判断)
    PAT (Advanced Level) Practice 1134 Vertex Cover (25分) (存边+标记点!!)
    PAT (Advanced Level) Practice 1133 Splitting A Linked List (25分) (静态链表的遍历)
    PAT (Advanced Level) Practice 1139 First Contact (30分) (unordered_map用来标记+哈希)
    PAT (Advanced Level) Practice 1132 Cut Integer (20分) (atoi、stoi区别、stringstream使用)
    PAT (Advanced Level) Practice 1138 Postorder Traversal (25分) (不键树、法一找规律法二先序中序变后序)
    区间DP学习 LibreOJ-10147 石子合并
    2020 Nowcoder Training
    UVA1347 Tour 动态规划
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066490.html
Copyright © 2011-2022 走看看