ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Django系列之中间件Middleware-02

2019-10-23 20:54:44  阅读:207  来源: 互联网

标签:02 process request Middleware 中间件 middleware self response


文章目录
1. 前言
2. 中间件的父类
3. 加载中间件
4. 中间件的调用逻辑
5. 总结
参考文献
1. 前言
在之前django的学习中,有两个术语FBV和CBV。

FBV(function base views) 就是在视图里使用函数处理请求。
CBV(class base views) 就是在视图里使用类处理请求。

2. 中间件的父类
在Django的文档中,推荐我们在自定义的中间件继承MiddlewareMixin这个类,下面是这个的源码。

# django/django/utils/deprecation.py
class MiddlewareMixin:
def __init__(self, get_response=None):
self.get_response = get_response
super().__init__()

def __call__(self, request):
response = None
# 若实例对象中具有'process_request'属性,则调用该方法
if hasattr(self, 'process_request'):
response = self.process_request(request)
response = response or self.get_response(request)
# 若实例对象中具有'process_response'属性,则调用该方法
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
从上面的源码可以看出,当调用中间件的实例时,如果中间件的实例中有对应的钩子函数,则先调用process_request,然后调用传入的可调用对象get_response,最后调用process_response。

3. 加载中间件
用过django的小伙伴应该都知道,创建完django项目之后,在项目目录下有一个setting.py这是包含了本项目的所有配置信息的文件。

# 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',
'custom.M1', # 自定义中间件1
'custom.M2', # 自定义中间件2
]
1
2
3
4
5
6
7
8
9
10
11
12
django源码中加载中间件的代码:

# django/django/core/handlers/base.py
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE.
Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._view_middleware = [] # 中间件的process_view()方法都添加到这
self._template_response_middleware = [] # 中间件的process_template_response()方法都添加到这
self._exception_middleware = [] # 中间件的process_exception()方法都添加到这

handler = convert_exception_to_response(self._get_response) # 装饰self._get_response,作用是添加了异常捕获功能
for middleware_path in reversed(settings.MIDDLEWARE): # 从配置文件中获得MIDDLEWARE变量中的所有中间件(字符串类型),反序嗷。
middleware = import_string(middleware_path) # 根据middleware字符串导入middleware(中间件的类)
try:
mw_instance = middleware(handler) # 创建中间件类的实例,并未调用实例噢self.__call__()方法。
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'): # 将中间件实例中的process_view实例方法加入list中
self._view_middleware.insert(0, mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'): # 将中间件实例中的process_template_response实例方法加入list中
self._template_response_middleware.append(mw_instance.process_template_response)
if hasattr(mw_instance, 'process_exception'): # 将中间件实例中的process_exception实例方法加入list中
self._exception_middleware.append(mw_instance.process_exception)

handler = convert_exception_to_response(mw_instance) # 装饰mw_instace实例,作用是添加了异常捕获功能

# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler # 装饰之后的返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
图片来自 【Django】Django架构流程分析


上面的load_middleware()的作用如上面的洋葱图所示,按照setting.py中MIDDLEWARE中的中间件的顺序,由外而内的包裹了_get_response(),而_get_response()中包含了view函数的调用。

解析URL获得对应的视图函数,调用process_view(),process_exception(),process_template_response()中间件和视图函数。

def _get_response(self, request):
"""
Resolve and call the view, then apply view, exception, and
template_response middleware. This method is everything that happens
inside the request/response middleware.
"""
response = None
# 根据URL进行解析获得URL对应的视图函数
if hasattr(request, 'urlconf'):
urlconf = request.urlconf
set_urlconf(urlconf)
resolver = get_resolver(urlconf)
else:
resolver = get_resolver()

resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match # 视图函数,位置参数和关键字参数
request.resolver_match = resolver_match

# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
break

if response is None:
wrapped_callback = self.make_view_atomic(callback)
try:
response = wr
response = self.process_exception_by_middleware(e, request)

# Complain if the view returned None (a common error).
if response is None:
if isinstance(callback, types.FunctionType): # FBV
view_name = callback.__name__
else: # CBV
view_name = callback.__class__.__name__ + '.__call__'

raise ValueError(
"The view %s.%s didn't return an HttpResponse object. It "
"returned None instead." % (callback.__module__, view_name)
)

# If the response supports deferred rendering, apply template
# response middleware and then render the response
elif hasattr(response, 'render') and callable(response.render):
for middleware_method in self._template_response_middleware:
response = middleware_method(request, response)
# Complain if the template response middleware returned None (a common error).
if response is None:
raise ValueError(
"%s.process_template_response didn't return an "
"HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__)
)

try:
response = response.render()
except Exception as e:
response = self.process_exception_by_middleware(e, request)

return response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
get_response()是WSGIHandler处理请求调用的函数

def get_response(self, request):
"""Return an HttpResponse object for the given HttpRequest."""
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF)
response = self._middleware_chain(request)
response._closable_objects.append(request)
if response.status_code >= 400:
log_response(
'%s: %s', response.reason_phrase, request.path,
response=response,
request=request,
)
return response
1
2
3
4
5
6
7
8
9
10
11
12
13
4. 中间件的调用逻辑
图片均来自 百度

源码中中间件的调用逻辑如下图所示:

钩子函数的执行顺序是(返回response时除外,返回response直接跳到process_template_response()、process_response()):

process_request()
process_view()
process_template_response()/process_exception()
process_response()
在每个钩子函数中,各中间件钩子函数的执行顺序(返回response时除外,返回response直接跳到process_template_response()、process_response()):

process_request()、process_view()顺序执行,也就是是说,先调用中间件1的process_request(),再调用中间件2的process_request(),process_view()也是一样。

process_template_response()、process_response()、process_exception()是逆序执行,先调用中间件2的``process_template_response(),再调用中间件1的process_template_response()。

django的整体流程图如下所示:


5. 总结
1
2
3
3
4
4
process_request
process_view
view
process_exception
process_template_response
process_response
process_request1
process_request2
process_view1
process_view2
view
process_template_response1
process_template_response2
process_exception1
process_exception2
process_response1
process_response2

标签:02,process,request,Middleware,中间件,middleware,self,response
来源: https://www.cnblogs.com/java67/p/11728759.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有