中间件的概念
中间件顾名思义, 是介于 request 与 response 处理之间的一道处理过程, 相对比较轻量级, 并且在全局上改变 django 的输入与输出. 因为改变的是全局, 所以需要谨慎实用, 用不好会影响到性能.
Django 的中间件的定义:
Middleware is a framework of hooks into Django's request/response processing. <br>It's a light, low-level "plugin" system for globally altering Django's input or output.
如果你想修改请求, 例如被传送到 view 中的 HttpRequest 对象. 或者你想修改 view 返回的 HttpResponse 对象, 这些都可以通过中间件来实现.
可能你还想在 view 执行之前做一些操作, 这种情况就可以用 middleware 来实现.
Django 默认的 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',
- ]
每一个中间件都有自己具体的功能.
自定义中间件
中间件中可以定义 5 个方法, 分别是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response
- 1,process_request,process_response
当用户发起请求的时候会依次经过所有的的中间件, 这个时候的请求时 process_request, 最后到达 views 的函数中, views 函数处理后, 在依次穿过中间件, 这个时候是 process_response, 最后返回给请求者.
上述截图中的中间件都是 django 中的, 我们也可以自己定义一个中间件, 我们可以自己写一个类, 但是必须继承 MiddlewareMixin
需要导入
from django.utils.deprecation import MiddlewareMixin
- in views:
- def index(request):
- print("view 函数...")
- return HttpResponse("OK")
- in Mymiddlewares.py:
- from django.utils.deprecation import MiddlewareMixin
- from django.shortcuts import HttpResponse
- class Md1(MiddlewareMixin):
- def process_request(self,request):
- print("Md1 请求")
- def process_response(self,request,response):
- print("Md1 返回")
- return response
- class Md2(MiddlewareMixin):
- def process_request(self,request):
- print("Md2 请求")
- #return HttpResponse("Md2 中断")
- def process_response(self,request,response):
- print("Md2 返回")
- return response
输出:
Md1 请求
Md2 请求
view 函数...
Md2 返回
Md1 返回
注意: 如果当请求到达请求 2 的时候直接不符合条件返回, 即 return HttpResponse("Md2 中断"), 程序将把请求直接发给中间件 2 返回, 然后依次返回到请求者, 结果如下:
返回 Md2 中断的页面, 后台打印如下:
Md1 请求
Md2 请求
Md2 返回
Md1 返回
2,process_view
process_view(self, request, callback, callback_args, callback_kwargs)方法介绍
(1)执行完所有中间件的 request 方法'
(2)url 匹配成功
(3)拿到 视图函数的名称, 参数,(注意不执行) 再执行 process_view()方法
(4)最后去执行视图函数
方法一,
- from django.utils.deprecation import MiddlewareMixin
- from django.shortcuts import HttpResponse
- class Md1(MiddlewareMixin):
- def process_request(self,request):
- print("Md1 请求")
- #return HttpResponse("Md1 中断")
- def process_response(self,request,response):
- print("Md1 返回")
- return response
- def process_view(self, request, callback, callback_args, callback_kwargs):
- print("Md1view")
- class Md2(MiddlewareMixin):
- def process_request(self,request):
- print("Md2 请求")
- return HttpResponse("Md2 中断")
- def process_response(self,request,response):
- print("Md2 返回")
- return response
- def process_view(self, request, callback, callback_args, callback_kwargs):
- print("Md2view")
输出:
Md1 请求
Md2 请求
Md1view
Md2view
view 函数...
Md2 返回
Md1 返回
过程分析:
当最后一个中间的 process_request 到达路由关系映射之后, 返回到中间件 1 的 process_view, 然后依次往下, 到达 views 函数, 最后通过 process_response 依次返回到达用户.
process_view 可以用来调用视图函数:
- class Md1(MiddlewareMixin):
- def process_request(self,request):
- print("Md1 请求")
- #return HttpResponse("Md1 中断")
- def process_response(self,request,response):
- print("Md1 返回")
- return response
- def process_view(self, request, callback, callback_args, callback_kwargs):
- # return HttpResponse("hello")
- response=callback(request,*callback_args,**callback_kwargs)
- return response
输出:
Md1 请求
Md2 请求
view 函数...
Md2 返回
Md1 返回
注意: process_view 如果有返回值, 会越过其他的 process_view 以及视图函数, 但是所有的 process_response 都还会执行.
3,process_exception
process_exception(self, request, exception)方法
- M1.request
- M2.request
- M1.process_view
- M2.process_view
执行 index
M2 的 process_exception
M1 的 process_exception
- Internal Server Error: /index/
- Traceback (most recent call last):
- File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
- response = get_response(request)
- File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
- response = self.process_exception_by_middleware(e, request)
- File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
- response = wrapped_callback(request, *callback_args, **callback_kwargs)
- File "F:\untitled1\app01\views.py", line 7, in index
- int("ok")
- ValueError: invalid literal for int() with base 10: 'ok'
- M2.response
- M1.response
- [03/Jul/2017 16:43:59] "GET /index/ HTTP/1.1" 500 62663
1, 执行完所有 request 方法
2, 执行 所有 process_view 方法
3, 如果视图函数出错, 执行 process_exception(最终 response,process_exception 的 return 值)
如果 process_exception 方法有了 返回值 就不再执行 其他中间件的 process_exception, 直接执行 response 方法响应
4. 执行所有 response 方法
5. 最后返回 process_exception 的返回值
输出:
- M1.request
- M2.request
- M1.process_view
- M2.process_view
执行 index
M2 的 process_exception (有了 return 值, 直接执行 response)
- M2.response
- M1.response
process_exception 的应用
在视图函数执行出错时, 返回错误信息. 这样页面就不会 报错了!
- class M1(MiddlewareMixin):
- def process_request(self, request):
- print('M1.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M1.process_view")
- def process_response(self, request, response):
- print('M1.response')
- return response
- def process_exception(self, request,exception):
- print('M1 的 process_exception')
- class M2(MiddlewareMixin):
- def process_request(self, request):
- print('M2.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M2.process_view")
- def process_response(self, request, response):
- print('M2.response')
- return response
- def process_exception(self, request, exception):
- print('M2 的 process_exception')
- return HttpResponse('出错了兄弟!!!')
流程图如下:
当 views 出现错误时:
- 4,process_template_response()
- from django.utils.deprecation import MiddlewareMixin
- from django.shortcuts import HttpResponse
- class M1(MiddlewareMixin):
- def process_request(self, request):
- print('M1.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M1.process_view")
- def process_response(self, request, response):
- print('M1.response')
- return response
- def process_exception(self, request,exception):
- print('M1 的 process_exception')
- class M2(MiddlewareMixin):
- def process_request(self, request):
- print('M2.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M2.process_view")
- def process_response(self, request, response):
- print('M2.response')
- return response
- def process_exception(self, request, exception):
- print('M2 的 process_exception')
- def process_template_response(self,request,response):
- print('M2process_template_response')
- return response
process_template_response()默认不执行
rocess_template_response()特性
只有在视图函数的返回对象中有 render 方法才会执行!
并把对象的 render 方法的返回值返回给用户 (注意不返回视图函数的 return 的结果了, 而是返回视图函数 return 值(对象) 的 render 方法)
- from django.utils.deprecation import MiddlewareMixin
- from django.shortcuts import HttpResponse
- class M1(MiddlewareMixin):
- def process_request(self, request):
- print('M1.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M1.process_view")
- def process_response(self, request, response):
- print('M1.response')
- return response
- def process_exception(self, request,exception):
- print('M1 的 process_exception')
- class M2(MiddlewareMixin):
- def process_request(self, request):
- print('M2.request')
- def process_view(self, request,callback,callback_args,callback_kwargs ):
- print("M2.process_view")
- def process_response(self, request, response):
- print('M2.response')
- return response
- def process_exception(self, request, exception):
- print('M2 的 process_exception')
- def process_template_response(self,request,response): #如果视图函数中的返回值 中有 render 方法, 才会执行 process_template_response
- print('M2process_template_response')
- return response
视图函数
- from django.shortcuts import render,HttpResponse
- # Create your views here.
- class Foo():
- def __init__(self,requ):
- self.req=requ
- def render(self):
- return HttpResponse('OKKKK')
- def index(request):
- print("执行 index")
- obj=Foo(request)
- return obj
应用:
既然 process_template_respnse, 不返回视图函数的 return 的结果, 而是返回视图函数 return 值 (对象) 的 render 方法;(多加了一个环节)
就可以在 这个视图函数返回对象的 render 方法里, 做返回值的二次加工了! 多加工几个, 视图函数就可以随便使用了!
- (好比 喷雾器有了多个喷头, 换不同的喷头喷出不同水, 返回值就可以也组件化了)
- from django.shortcuts import render,HttpResponse
- # Create your views here.
- class Dict(): #对视图函数返回值做二次封装 !!
- def __init__(self,requ,msg):
- self.req=requ
- self.msg=msg
- def render(self):
- a=self.msg #在 render 方法里面 把视图函数的 返回值 制作成字典 , 列表等...
- # 如果新增了其他 一个视图函数直接, return 对象 即可! 不用每个视图函数都写 制作字典 列表 拼接的逻辑了
- return HttpResponse(a) #
- def index(request):
- print("执行 index")
- obj=Dict(request,"vv")
- return obj
中间件应用场景
由于中间件工作在 视图函数执行前, 执行后 (像不像所有视图函数的装饰器!) 适合所有的请求 / 一部分请求做批量处理
1, 做 IP 限制
放在 中间件类的列表中, 阻止某些 IP 访问了;
2,URL 访问过滤
如果用户访问的是 login 视图(放过)
如果访问其他视图(需要检测是不是有 session 已经有了放行, 没有返回 login), 这样就省得在 多个视图函数上写装饰器了!
3, 缓存(还记得 CDN 吗?)
客户端请求来了, 中间件去缓存看看有没有数据, 有直接返回给用户, 没有再去逻辑层 执行视图函数
来源: https://www.cnblogs.com/mjiu/p/10234160.html