Django中间件深入理解

​ 今天在网上搜寻中间件方法的时候,看到有些中间件并不是按照之前我学习的那几个钩子函数来实现的,而是直接写了一个 __init__和一个__call__方法来实现的,决定看一下,为什么这么实现可以变成一个中间件。

平常实现方式

一般我们实现我们都是继承了 MiddlewareMixin然后实现相关的钩子函数。

MiddlewareMixin源码

class MiddlewareMixin:
    # middleware_instance = A(B(C(D(_get_response))))
    # self.get_respons = B(C(D(_get_response))
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    # 通过__call__实现一种类似递归调用的方式
    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            # A(B(C(D(_get_response))))(request)会调用__call__(request)中的逻辑执行
            # 1. A(B(C(D(_get_response)))).process_request(request)  中间件A的process_request()方法被执行返回none
            response = self.process_request(request)
        if not response:
            # 2. response为None self.get_response 指的是A的B(C(D(_get_response)),B(C(D(_get_response))(request) 又会去调用
            #  __call__(request) ——> B(C(D(_get_response)).process_request(request)  中间件B的process_request()方法被执行返回none
            #  再次进入if not response分支 C(D(_get_response)(request)直到最后执行 _get_response(request)方法
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

这里的__call__方法只处理了 process_requestprocess_response其他的几个钩子函数都是在 self.get_response中处理的

Django启动的时候

Django启动的时候,会先实例化 WSGIHander这个类

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()

self.load_middleware

load_middleware(self, is_async=False):
        """
        Populate middleware lists from settings.MIDDLEWARE.

        Must be called after the environment is fixed (see __call__ in subclasses).
        """
        self._view_middleware = []
        self._template_response_middleware = []
        self._exception_middleware = []

        #django 3.0 会判断是否是异步
        get_response = self._get_response_async if is_async else self._get_response
        handler = convert_exception_to_response(get_response)
        handler_is_async = is_async
        # 开始遍历 settings中设置的 中间件,反序遍历
        for middleware_path in reversed(settings.MIDDLEWARE):
            # 中间件对象
            middleware = import_string(middleware_path)
            middleware_can_sync = getattr(middleware, 'sync_capable', True)
            middleware_can_async = getattr(middleware, 'async_capable', False)
            if not middleware_can_sync and not middleware_can_async:
                raise RuntimeError(
                    'Middleware %s must have at least one of '
                    'sync_capable/async_capable set to True.' % middleware_path
                )
            elif not handler_is_async and middleware_can_sync:
                middleware_is_async = False
            else:
                middleware_is_async = middleware_can_async
            try:
                # Adapt handler, if needed.
                handler = self.adapt_method_mode(
                    middleware_is_async, handler, handler_is_async,
                    debug=settings.DEBUG, name='middleware %s' % middleware_path,
                )
                # 实例化中间件对象
                mw_instance = middleware(handler)
            except MiddlewareNotUsed as exc:
                if settings.DEBUG:
                    if str(exc):
                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                    else:
                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                continue

            if mw_instance is None:
                raise ImproperlyConfigured(
                    'Middleware factory %s returned None.' % middleware_path
                )
						# 如果中间件有对应的钩子方法那么我们就把,对应的方法放到列表中。
            if hasattr(mw_instance, 'process_view'):
                self._view_middleware.insert(
                    0,
                    self.adapt_method_mode(is_async, mw_instance.process_view),
                )
            if hasattr(mw_instance, 'process_template_response'):
                self._template_response_middleware.append(
                    self.adapt_method_mode(is_async, mw_instance.process_template_response),
                )
            if hasattr(mw_instance, 'process_exception'):
                # The exception-handling stack is still always synchronous for
                # now, so adapt that way.
                self._exception_middleware.append(
                    self.adapt_method_mode(False, mw_instance.process_exception),
                )
						# 此处可以看成 第一次[中间件1(get_response)],循环第二次[中间件2(中间件1(get_response))] 一次类推
            handler = convert_exception_to_response(mw_instance)
            handler_is_async = middleware_is_async

        # Adapt the top of the stack, if needed.
        handler = self.adapt_method_mode(is_async, handler, handler_is_async)
        # We only assign to this when initialization is complete as it is used
        # as a flag for initialization being complete.
        
        # 这个就是 中间件2(中间件1(get_response))  套娃
        self._middleware_chain = handler

之后 self._middleware_chain 会在BaseHandlerget_response方法中被调用。

class BaseHandler:
    def get_response(self, request):

        set_urlconf(settings.ROOT_URLCONF)

        # 此函数完成对中间件的各个函数调用已经视图函数的调用
        # 首先依次调用中间件A,B,C,D的process_request

        # 之后调用_get_respones()方法,_get_respones()方法又会调用在load_middleware()方法中从中间件中添加的process_view函数,
        # process_template_response和 process_exception函数

        # 最后依次调用中间件的process_response方法
        response = self._middleware_chain(request)

        response._closable_objects.append(request)
        ...
        return response

    def _get_response(self, request):
        ...
        return response

之后就实现了一种类似递归的调用。

图一

posted @ 2020-10-22 14:35  沈俊杰  阅读(134)  评论(0编辑  收藏  举报