开篇
中间件是什么?
中间件的本质是一个类实例对象或者一个函数对象,这些对象提供过滤请求、响应、处理异常等功能。重点关键字:过滤 1 中间件可以是类的形式也可以是函数的形式,见官网说明
上结论先
从请求到响应阶段 都可以进行拦截 第一阶段 处理 process_request 列表 返回None 或者HttpResponse对象 第二阶段 通过路由映射关系表获取视图函数地址 获得函数(进入视图预处理链process_view) 或者没有(404)--进入响应处理链 第三阶段 处理 process_view列表(前提是已经有匹配到的视图函数) process_view 返回None或者HttpReponse 第四阶段 处理视图函数 生成响应 第五阶段 处理异常检测 处理异常 返回响应或者None, None 表示交给下一层处理异常 第六阶段 处理 process_response 列表 不管从哪里发出的响应都要从响应链走,要么从中间走,要么从底层走 中间件类提供过滤请求、响应的钩子,即process_request、process_response等,所有钩子按照中间件类在中间件列表中的顺序组成新的钩子列表,process_response响应钩子、process_exception异常处理钩子是反向执行的
上代码(代码所在的文件在项目中的位置不重要,重要的是能找到中间件类的路径)
# 1.11 版本的兼容写法,当然你也可以自己手写一个类,不是很麻烦,我使用继承
# appname/middleware.py
# 每一个类都可以根据需要提供不同的钩子,这些钩子组成钩子列表
from django.utils.deprecation import MiddlewareMixin
class Row1(MiddlewareMixin):
def process_request(self, request):
print('row1 请求', request)
# response = HttpResponse("row1 response")
# return response
def process_response(self, request, response):
print('row1 响应', request, response)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('row1 view', view_func)
class Row2(MiddlewareMixin):
def process_request(self, request):
print('row2 请求', request)
def process_response(self, request, response):
print('row2 响应', request, response)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('row2 view', view_func)
def process_exception(self, request, exception):
print('row2 exception', exception)
return HttpResponse(exception);
class Row3(MiddlewareMixin):
def process_request(self, request):
print('row3 请求', request)
def process_response(self, request, response):
print('row3 响应', request, response)
if response.status_code == 404:
response = HttpResponse('404')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('row3 view', view_func)
def process_exception(self, request, exception):
print('row3 exception', exception)
- 上配置
- MIDDLEWARE中 中间件类所处的顺序很重要,决定了每个中间件类提供的钩子的执行顺序
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',
'booktest.middleware.Row1',
'booktest.middleware.Row2',
'booktest.middleware.Row3',
]
- 调用的view函数
# Create your views here.
def index(request):
# raise Exception('异常')
return HttpResponse("<b>世界如此美妙<b>")
- 上运行结果
July 29, 2017 - 05:17:13
Django version 1.11, using settings 'test6.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
生成应用
row1 请求 <WSGIRequest: GET '/'>
row2 请求 <WSGIRequest: GET '/'>
row3 请求 <WSGIRequest: GET '/'>
row1 view <function index at 0x1044e36a8>
row2 view <function index at 0x1044e36a8>
row3 view <function index at 0x1044e36a8>
row3 响应 <WSGIRequest: GET '/'> <HttpResponse status_code=200, "text/html; charset=utf-8">
row2 响应 <WSGIRequest: GET '/'> <HttpResponse status_code=200, "text/html; charset=utf-8">
row1 响应 <WSGIRequest: GET '/'> <HttpResponse status_code=200, "text/html; charset=utf-8">
[29/Jul/2017 05:17:55] "GET / HTTP/1.1" 200 24
其他
感兴趣的话可以手动抛出异常来看看效果 1 在process_request 阶段, 每个钩子都可以返回None或者HttpResponse对象(自己构造一个),如果返回None,则下一个钩子接着处理,直到URL关系映射表执行匹配操作;如果返回HttpResponse 则从当前中间件层开始反向返回结果,最核心层的view函数不会被执行,当前中间件层的下面中间件类提供的处理响应钩子也不会被执行(1.11版本) 2 当所有的process_request钩子执行完毕,都返回None,则进入路由关系映射匹配阶段,即根据请求路径找能处理响应的view函数,有两个结果:找到了--->进入process_view钩子列表处理阶段;没找到----->进入process_response钩子列表处理阶段 3 在process_view 处理阶段可以,每个钩子可以返回None也可以返回HttpResponse 对象,参上 4 在process_response 阶段,我们可以篡改响应,比如没找到视图函数,我们可以给捏造一个扔给客户 5 当process_request--->路由关系映射找到视图函数--->process_view 都处理完成了,并且找到了视图函数,中间没有使用钩子构造响应,则view函数开始工作:执行业务逻辑代码,从数据库拉去数据,给模板填坑,构造响应对象 6 5这个过程可能抛出异常,抛出异常则进入异常钩子列表process_exception,如果所有的异常处理钩子都不能处理异常,程序把异常通过process_response 钩子列表扔给客户
以上 就是整个流程,当然,没有涉及process_template_response钩子列表
上个简图 input/output
每一个中间件都想一张过滤网
上个网络盗图
* 上第二个网络图
收尾
我们拿这些中间件干什么呢?
答:玩 认真的回答:那它做IP拦截,客户端设备识别,过滤恶意请求等等
- 上面的介绍并不全面,还有很多细节没介绍,但不影响对请求/响应整个流程的理解