• Middleware


    中间件是一个钩子框架,是介于request与response处理之间的一道处理过程,它们可以介入Django 的请求和响应处理过程。它是一个轻量级、底层的“插件”系统,用于在全局修改Django 的输入或输出。

    每个中间件组件负责完成某个特定的功能。例如,Django 包含的一个中间件组件AuthenticationMiddleware ,它使用会话将用户和请求关联起来。 

    我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:

    激活中间件

    要激活一个中间件组件,需要把它添加到Django 配置文件中的MIDDLEWARE_CLASSES 元组中。

    MIDDLEWARE_CLASSES中,每一个中间件组件用字符串的方式描述:一个完整的Python全路径加上中间件的类名称。例如,使用 django-admin startproject创建工程的时候生成的默认值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    MIDDLEWARE_CLASSES = (
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'django.middleware.security.SecurityMiddleware',
    )

    Django的程序中,中间件不是必需的 —— 只要你喜欢,MIDDLEWARE_CLASSES可以为空 —— 但是强烈推荐你至少使用CommonMiddleware

    MIDDLEWARE_CLASSES中的顺序非常重要,因为一个中间件可能依赖于另外一个。例如,AuthenticationMiddleware在会话中储存已认证的用户。所以它必须在SessionMiddleware之后运行。一些关于Django中间件类的顺序的常见提示,请见中间件排序

    钩子和应用的顺序

    在请求阶段中,调用视图之前,Django会按照MIDDLEWARE_CLASSES中定义的顺序自顶向下应用中间件。会用到两个钩子:

    在响应阶段中,调用视图之后,中间件会按照相反的顺序应用,自底向上。会用到三个钩子:

      

    如果你愿意的话,你可以把它想象成一颗洋葱:每个中间件都是包裹视图的一层“皮”。

    每个钩子的行为接下来会描述。

    编写自己的中间件

    #---------------------------------------------views.py
    def hello(req):
        print('views')
        return HttpResponse('ok')
    
    #---------------------------------------------settings.py
    MIDDLEWARE_CLASSES = [
        'mymiddle_ware.mymiddle.MiddleTest',
        'mymiddle_ware.mymiddle.MiddleTest2',
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
    ]
    #---------------------------------------------mymiddle.py
    
    from django.shortcuts import render,HttpResponse
    
    class MiddleTest(object):
    
        def process_request(self,req):
    
            print('process_request....')
            # return HttpResponse('你好')  #越过其它中间件和views,去经过response系列转运
    
        def process_response(self,req,res):
            print('process_response....')
            return res  ##res即views返回的 HttpResponse('ok')对象
    
    class MiddleTest2(object):
    
        def process_request(self,req):
    
            print('process_request2....')
    
        def process_response(self,req,res):
            print('process_response2....')
    
            return res  #res即views返回的 HttpResponse('ok')对象
    
        def process_exception(self,request, exception):
    
            print('exception',exception)
            return HttpResponse(exception)
    View Code

    编写自己的中间件很容易的。每个中间件组件是一个独立的Python 类,你可以定义下面这些方法中的一个或多个: 

    process_request

    process_request(request)

    request是一个HttpRequest 对象。

    在Django决定执行哪个视图之前,process_request()会在每个请求上调用。

    它应该返回一个None 或一个HttpResponse对象。如果返回None,Django会继续处理这个请求,执行其它process_request()中间件,然后process_view()中间件,最后是对应的视图。如果它返回一个HttpResponse对象,Django 就不用再去调用其它的request、view 或exception 中间件,或对应的视图;它将对HttpResponse 运用响应阶段的中间件,并返回结果。

    process_view

    process_view(request, view_func, view_args, view_kwargs)

    request是一个HttpRequest对象。view_func是 Django会调用的一个Python的函数。(它是一个真实的函数对象,不是函数的字符名称。) view_args是一个会被传递到视图的位置参数列表,而view_kwargs 是一个会被传递到视图的关键字参数字典。 view_args和 view_kwargs 都不包括第一个视图参数(request)。

    process_view()会在Django 调用视图之前被调用。

    它将返回None 或一个HttpResponse 对象。如果返回None,Django 将会继续处理这个请求,执行其它的process_view() 中间件,然后调用对应的视图。如果返回一个HttpResponse对象,Django 就不用再去调用其它的view 或exception 中间件,或对应的视图;它将对HttpResponse 运用响应阶段的中间件,并返回结果。

    注意

    在中间件内部,从process_request 或process_view 中访问request.POST 或request.REQUEST 将阻碍该中间件之后的所有视图无法修改请求的上传处理程序,一般情况下要避免这样使用。

    CsrfViewMiddleware可以被认为是个例外,因为它提供csrf_exempt() 和csrf_protect()两个装饰器,允许视图显式控制在哪个点需要开启CSRF验证。

    process_template_response 

    process_template_response(request, response)

    request是一个HttpRequest对象。response是一个TemplateResponse对象(或等价的对象),由Django视图或者中间件返回。

    如果响应的实例有render()方法,process_template_response()在视图刚好执行完毕之后被调用,这表明了它是一个TemplateResponse对象(或等价的对象)。

    这个方法必须返回一个实现了render方法的响应对象。它可以修改给定的response对象,通过修改 response.template_nameresponse.context_data或者它可以创建一个全新的 TemplateResponse或等价的对象。

    你不需要显式渲染响应 —— 一旦所有的模板响应中间件被调用,响应会自动被渲染。

    在一个响应的处理期间,中间件以相反的顺序运行,这包括process_template_response()

    process_response

    process_response(request, response)

    request是一个HttpRequest对象。response是Django视图或者中间件返回的HttpResponse或者StreamingHttpResponse对象。

    process_response()在所有响应返回浏览器之前被调用。

    这个方法必须返回HttpResponse或者StreamingHttpResponse对象。它可以改变已有的response,或者创建并返回新的HttpResponseStreamingHttpResponse对象。

    不像 process_request()process_view()方法,即使同一个中间件类中的process_request()process_view()方法会因为前面的一个中间件返回HttpResponse而被跳过,process_response()方法总是会被调用。特别是,这意味着你的process_response()方法不能依赖于process_request()方法中的设置。

    最后,记住在响应阶段中,中间件以相反的顺序被应用,自底向上。意思是定义在MIDDLEWARE_CLASSES最底下的类会最先被运行。

    处理流式响应

    不像HttpResponseStreamingHttpResponse并没有content属性。所以,中间件再也不能假设所有响应都带有content属性。如果它们需要访问内容,他们必须测试是否为流式响应,并相应地调整自己的行为。

    if response.streaming:
        response.streaming_content = wrap_streaming_content(response.streaming_content)
    else:
        response.content = alter_content(response.content)

    注意

    我们需要假设streaming_content可能会大到在内存中无法容纳。响应中间件可能会把它封装在新的生成器中,但是一定不要销毁它。封装一般会实现成这样:

    def wrap_streaming_content(content):
        for chunk in content:
            yield alter_content(chunk)
    View Code

    process_exception

    process_exception(request, exception)

    request是一个HttpRequest对象。exception是一个被视图中的方法抛出来的 Exception对象。

    当一个视图抛出异常时,Django会调用process_exception()来处理。process_exception()应该返回一个None或者一个HttpResponse对象。如果它返回一个HttpResponse对象,模型响应和响应中间件会被应用,响应结果会返回给浏览器。否则, 默认的异常处理机制将会被触发。

    再次提醒,在处理响应期间,中间件的执行顺序是倒序执行的,这包括process_exception如果一个异常处理的中间件返回了一个响应,那这个中间件上面的中间件都将不会被调用。

    __init__  

    大多数的中间件类都不需要一个初始化方法,因为中间件的类定义仅仅是为process_*提供一个占位符。如果你确实需要一个全局的状态那就可以通过__init__来加载。然后要铭记如下两个警告:
    
    Django初始化你的中间件无需任何参数,因此不要定义一个有参数的__init__方法。
    不像process_* 对每个请求都要调用,__init__ 只会被调用一次,就是在Web 服务器响应第一个请求的时候。
    标记中间件不被使用¶
    有时在运行时决定是否一个中间件需要被加载是很有用的。 在这种情况下,你的中间件中的 __init__方法可以抛出一个django.core.exceptions.MiddlewareNotUsed异常。Django会从中间件处理过程中移除这部分中间件,并且当DEBUG为True的时候在django.request记录器中记录调试信息。
    View Code

    应用

    from django.shortcuts import render,HttpResponse
    #项目 abcd 文件名 abcd/middleware.py
    
    class BlockedIpMiddleware(object):
        def process_request(self, request):
            if request.META['REMOTE_ADDR'] in getattr(settings, "BLOCKED_IPS", []):
                return HttpResponse('<h1>Forbbiden</h1>')
    
    #----settings.py
    MIDDLEWARE_CLASSES = (
        'abcd.middleware.BlockedIpMiddleware',
        #...其它的中间件
    )
    拦截器
  • 相关阅读:
    Windows性能计数器应用
    Azure Oracle Linux VNC 配置
    Azure 配置管理系列 Oracle Linux (PART6)
    Azure 配置管理系列 Oracle Linux (PART5)
    Azure 配置管理系列 Oracle Linux (PART4)
    Azure 配置管理系列 Oracle Linux (PART3)
    Azure 配置管理系列 Oracle Linux (PART2)
    vagrant多节点配置
    docker基本操作
    LINUX开启允许对外访问的网络端口命令
  • 原文地址:https://www.cnblogs.com/navysummer/p/8455016.html
Copyright © 2020-2023  润新知