Django中间件访问流程
前置知识点:
python内置函数warp: 不会改变函数结构, 防止函数的源数据丢失,如下图inner函数还会保存get_response的元数据 __name__ __doc__
后面的源码中就会有这样的例子, inner函数是闭包的返回函数,如果不加wrap,元数据就会被inner函数的数据取代
_init_启动django项目,
_call_网页请求到来时走_call_方法
进入父类的load_middleware()方法查看具体功能
这里try成功会保存response,失败的话会返回失败的情况下对应的response值
convert_exception_to_response正如它的名字一样,在失败的情况下还是会正常返回response,不会程序就此崩掉
class BaseHandler:
_view_middleware = None
_template_response_middleware = None
_exception_middleware = None
_middleware_chain = None
def 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 = []
get_response = self._get_response_async if is_async else self._get_response
# 刚上来get_response = self._get_response(路由匹配 + 视图函数)
handler = convert_exception_to_response(get_response)
# 刚上来 handler = self._get_response
handler_is_async = is_async
# 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',
# 'utils.md.KeLaMiddleware',
# ]
for middleware_path in reversed(settings.MIDDLEWARE):
# 第一次middleware_path = 'utils.md.KeLaMiddleware'
# 第二次 middleware_path = 'django.middleware.clickjacking.XFrameOptionsMiddleware',
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.
# 第一次 adapted_handler = handler = self._get_response
# 第二次 adapted_handler = handler = utils.md.KeLaMiddleware(self._get_response)
adapted_handler = self.adapt_method_mode(
middleware_is_async,
handler,
handler_is_async,
debug=settings.DEBUG,
name="middleware %s" % middleware_path,
)
# 第一次 mw_instance = utils.md.KeLaMiddleware(self._get_response)
# 第二次 mw_instance = django.middleware.clickjacking.XFrameOptionsMiddleware(utils.md.KeLaMiddleware(self._get_response))
mw_instance = middleware(adapted_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
else:
# 第一次 handler = adapted_handler = self._get_response
# 第二次 handler = adapted_handler = utils.md.KeLaMiddleware(self._get_response)
handler = adapted_handler
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),
)
# 第一次 handler = mw_instance = utils.md.KeLaMiddleware(self._get_response)
# 第二次 handler = mw_instance = django.middleware.clickjacking.XFrameOptionsMiddleware(utils.md.KeLaMiddleware(self._get_response))
# .....
# 最后一次handler = mw_instance = django.middleware.security.SecurityMiddleware(一层一层包住包到utils.md.KeLaMiddleware(self._get_response))
handler = convert_exception_to_response(mw_instance)
handler_is_async = middleware_is_async
# Adapt the top of the stack, if needed.
# 循环结束 handler = setting列表第一次套了一堆
handler = self.adapt_method_mode(is_async, handler, handler_is_async)
print(333, handler.__name__)
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
# 把handler封装进 self._middleware_chain
self._middleware_chain = handler
封装部分结束
self.middleware_chain = django.middleware.security.SecurityMiddleware(一层一层包住包到utils.md.KeLaMiddleware(self._get_response))
所以流程为
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',
'utils.md.KeLaMiddleware',
]
1. 走到第一个SecurityMiddleware中间件里的process_request获得response
如果是True直接返回,
否则request丢进第二个中间件SessionMiddleware里的process_request获得response
如果是True直接返回
否则request丢进第三个中间件CommonMiddleware里的process_request获得response
如果是True直接返回
否则
....
如果所有的process_request返回值都不是None,
django.middleware.security.SecurityMiddleware(一层一层包住包到utils.md.KeLaMiddleware(self._get_response))
就会先进到最后一个中间件中拿到get_response =self._get_response(路由匹配视图函数)
再进到倒数第二个中间件处理get_response.....
最后返回