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))
posted @ 2020-12-01 10:03  王寄鱼  阅读(97)  评论(0编辑  收藏  举报