二、中间件(middleware)

1.      中间件(middleware)

Django中的中间件主要实现一些附加功能,在request被用户handler处理前,以及用户handler处理后生存的response进行处理。因此大部分中间件的主要功能是实现了process_request或者process_response之一,当然也可以两者都实现,意味着该中间件涉及到处理的request和response的处理。

1.1       类视图

在中间件的类关系中,基本类是MiddlewareMixin,其他所有的中间件类都继承自该类,该类仅有一个成员变量get_response,该变量在连接各个中间件起着非常重要的作用。该类有两个成员函数:__init__和__call__,前者用于实现初始化,后者执行主要的功能。

    def __call__(self, request):

        response = None

        if hasattr(self, 'process_request'):

            response = self.process_request(request)

        if not response:

            response = self.get_response(request)

        if hasattr(self, 'process_response'):

            response = self.process_response(request, response)

        return response

其中process_request和process_response自不必多言,中间件需要实现的主要功能,通过hasattr()调用,判断当前中间件是否具有process_request和process_response,有则调用。

不同功能的中间件,根据要完成的功能,可以扩展自己的成员变量和成员函数,通常,自定义的成员函数被process_request和process_response调用,即这些自定义的成员函数通常不对外开放。

       其中,__init__成员函数有入参函数之一: get_response,这在后续的加载中间件时很重要好。

下图是中间件SecurityMiddleware类的类视图关系图,其他中间件的视图关系类似。

 

1.2       中间件初始化

在工程的配置文件(Project/Project/setting.py)中指定要使用的中间件,注意各插件在序列中的顺序,这决定了当请求到来时,各个中间件的执行顺序,排在最前面的中间件得到最先执行,最后的中间件最后执行。其表现通常如下所示:

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

]

下面来看,中间件是如何被加载和初始化的。class BaseHandler(object):中定义了load_middleware接口,具体细节如下:

handler = convert_exception_to_response(self._get_response)  /*handler[0]*/

for middleware_path in reversed(settings.MIDDLEWARE):
    middleware = import_string(middleware_path)

    mw_instance = middleware(handler)
    handler = convert_exception_to_response(mw_instance) /*handler[i]*/
self._middleware_chain = handler                    /*handler[end]*/

在上述例程中,开始遍历所有中间件之前,handler(即handler[0])赋值给调用实体的_get_response成员函数。                   (比如class WSGIHandler(base.BaseHandler),WSGIHandler. load_middleware()调用之后,handler[0] = WSGIHandler._get_response = BaseHandler._get_response())。遍历所有中间件过程中,加载并初始化(middleware()调用对应着__init__成员函数)中间件,因此中间件的get_response赋值为handler[i],注意middleware()返回一个中间件类实体,接着调用调用handler  = convert_exception_to_response (mw_instance),convert_exception_to_response只是对输入函数进行了容错封装,在分析逻辑时,可以简单看成输入函数本身,因此,可以看成handler = mw_instance(request),对于一个类实体调用即调用__call__成员函数,从目前来看,大部分的中间件并没有重载该成员函数,因此是直接调用基类的成员函数,即: MiddlewareMixin. __call__(self)。因此handler[i] = MiddlewareMixin. __call__(self)。注意该函数有一个self输入参数,各个中间件在调用时,传入该中间件对应的self实体,这样self.process_request, self.process_response的调用就分别对应着不同中间夹的处理函数。load_middleware()调用之后,各个中间件通过get_response链接起来,这样一个request请求到来时,可以顺序通过各个中间件依次进行处理,如下图所示:

 

在调用的最后,将self._middleware_chain = handler[end],类似于将中间件链表的链表头保存起来,下次处理时,从该链表头开始进行遍历处理。

1.3       中间件使用

各个中间件的调用顺序如下递归图所示:

 

在类视图一节中对__call__基类成员函数进行过介绍,该函数主要有先后执行的三个函数构成:process_request()、get_response()、process_response(),而get_response()通常指向下一个中间件的__call__成员函数(中间件链表的最后一个中间件除外,其get_response()指向handler[0]),由于各个中间件的get_response()这一特性(绝大部分指向基类__call__成员函数),使得中间件链表处理有点类似递归调用的感觉。A,B,A1,B1,A2,B2,C2,C1,C,这一递归调用顺序,决定了各个中间件处理的一些特点:

1、最先进行流程处理的中间件,其process_request()(如果存在的话)最先被执行,但是其process_response()(如果存在的话)却最后得到处理。

2、最后进行流程处理的中间件,其process_request()(如果存在的话)最后被执行,但是其process_response()(如果存在的话)紧接着得到处理。

3、在中间件处理流程中,如果出现某个中间件的process_request()返回了response,这种情况通常是处理过程中出现了异常情况,该中间件后续的中间件不再参与处理,直接调用该中间件的process_response()(如果存在的话),或者直接返回。

原文地址:https://www.cnblogs.com/fbli/p/5925071.html