Django学习之中间件

    django 中间件(middleware),在django中其实就是一个,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。在请求到达视图之前,会依次执行中间件,视图返回的响应,依次倒序执行中间件。django中的中间件可以定义5个方法,常用的为process_request和process_response。

中间件可以定义的五个方法

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)

    以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

 

自定义中间步骤

1、导入模块

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

2、自定义中间件

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse



class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MDl-->process_request')
    def process_response(self,request, response):
        print('MDl-->process_response')
        return response


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2-->process_request')
    def process_response(self, request,response):
        print('MD2-->process_response')
        return response

3、定义view函数

from django.shortcuts import render,HttpResponse


def test(request):
    print('views')
    return HttpResponse('ok')

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

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',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'md.md.MD1',
    'md.md.MD2',
]

    访问url可以看到执行结果

MDl-->process_request
MD2-->process_request
views
MD2-->process_response
MDl-->process_response

    可以看到有中间件是django的请求处理流程如下:

1、请求到来时先依次(按照MIDDLEWARE中的注册顺序,从前到后依次执行的。)执行中间件的process_reques方法。不同中间件之间传递的request都是同一个对象
2、执行view中对应函数
3、请求返回时依次倒序执行(按照MIDDLEWARE中的注册顺序倒序执行的)中间的process_response方法

中间件五个方法

process_request

    process_request 方法是用户请求进来时最先执行。process_request有一个参数,就是request,这个request和视图函数中的request是一样的。它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,那么下面的中间件将不会执行,后面的URL以及视图函数也不会执行,而将相应对象返回给浏览器。如果有多个中间件按照MIDDLEWARE中的注册顺序,从前到后依次执行process_request 方法。

    简单使用例子:判断用户ip是否在黑名单,如果在直接禁止访问

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class denyIP(MiddlewareMixin):
    def process_request(self, request):
        allowed_ip = ['192.168.1.1', ]
        # 允许/禁止访问的ip地址列表,判断请求ip, 放行/阻拦
        print(request.META.get('REMOTE_ADDR'))
        if request.META.get('REMOTE_ADDR') not in allowed_ip:
            #如果不在ip列表里直接return,后面的中间件和view中函数都不会执行
            return HttpResponse('您的IP地址无权访问')
        else:
            return None

 

process_response

    process_response 是view中函数处理完用户请求时返回响应时执行的。多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的。它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。默认情况下返回response, 即视图函数的返回值,如果在这个方法中自定义了返回值,将返回自定义返回值。

例子:

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print('MDl-->process_request')
    def process_response(self,request, response):
        print('MDl-->process_response')
        #return response
        return HttpResponse("第一个中间process_response方法定义的返回值")

 

 

 

process_request和process_response总结

1、中间件的process_request方法是在执行视图函数之前执行的。
2、当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
3、不同中间件之间传递的request都是同一个对象
4、多个中间件中的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并返回结果。

    process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

    当初中间件中有process_view方法时执行过程:

执行完process_request  →  路由分发(dispatch)  →  process_view  →  视图函数  → process_response
###########urls.py###############
url(r'^test/(\d+)/', md.test),
url(r'^test1/(?P<nid>\d+)/', md.test),
##########中间件###########
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print('MD2-->process_request')
    def process_response(self, request,response):
        print('MD2-->process_response')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('>=======process_view')
        print('view_func>=====',view_func)
        print('view_args>=====', view_args)
        print('view_kwargs>=====', view_kwargs)


###########view.py###############
def test(request,nid):
    print('view>====',nid)
    return HttpResponse('ok')

#########请求结果###########
请求http://127.0.0.1:8081/test/1/时

MD2-->process_request
>=======process_view
view_func>===== <function test at 0x0000000007525950>
view_args>===== ('1',)
view_kwargs>===== {}
view>==== 1
MD2-->process_response

请求http://127.0.0.1:8081/test1/1/
MD2-->process_request
>=======process_view
view_func>===== <function test at 0x0000000007515950>
view_args>===== ()
view_kwargs>===== {'nid': '1'} 
view>==== 1
MD2-->process_response

process_exception

process_exception(self, request, exception)

该方法两个参数:
  一个HttpRequest对象
  一个exception是视图函数异常产生的Exception对象。

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

中间件完整的执行流程


请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,
就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,
而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,
那么第4,
5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。 process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,
process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。加入中间件3 的process_view方法返回了HttpResponse对象,
则4,
5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

CSRF_TOKEN跨站请求伪造

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF。django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  在配置文件中启用中间件 django.middleware.csrf.CsrfViewMiddleware

csrf:局部禁用,局部使用
    使用装饰器(FBV)
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    -局部使用,全局得禁用
           @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
           @csrf_protect
           def csrf_disable(request):
                print(request.POST)
                return HttpResponse('ok')
     -局部禁用,全局得使用
            @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
            @csrf_exempt
            def csrf_disable(request):
                print(request.POST)
                return HttpResponse('ok')


    
在form表单中应用
html中设置Token:
  {% 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表单中应用
<input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
        var csrftoken = $.cookie('csrftoken');
 
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>

 

    

posted @ 2019-12-20 15:54  泉love水  阅读(185)  评论(0编辑  收藏  举报