深入理解Django的中间件middleware


Posted in Python onMarch 14, 2018

本文讲述的内容基于 Django 1.11

摘要

Django 中的中间件(middleware),是一个镶嵌到Django的request/response处理机制中的一个hooks框架,是一个修改django全局输入输出的一个底层插件系统。让我们可以自定义想要的一些功能来处理用户的请求。

在Django中,中间件其实就是一个类,在类中包含一组特定的功能,在请求到来或者结束时,Django会根据我们定义的中间件规则执行中间件中对应的方法,一个 Django 项目默认激活的中间件在我们项目中的配置中可以看到是这个样子的:

settings.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',
]

MIDDLEWARE这里列表中的每一个元素,其实就是一个个单独的中间件,举例来说:django.middleware.csrf.CsrfViewMiddleware这个中间件,作用就是在我们的 form 表单提交请求的时候,提交的时候必须要带上csrf_token,否则就不会正确提交。

中间件使用也需要讲究顺序,下一层依赖上一层的封装,例如,我们的AuthenticationMiddleware是一个认证中间件,在session 中保存认证用户的信息,但是他必须依赖于SessionMiddleware才可以被正确使用,所以他也必须在SessionMiddleware之后。但是具体的顺序问题可以参考这里

中间件结构

中间件类中需要包含以下处理方法:

1. process_request(self, request)
2. process_view(self, request, callback, callback_args, callback_kwargs)
3. process_template_response(self, request, response)
4. process_exception(self, request, exception)
5. process_response(self, request, response)

执行过程

以我们的项目中默认中间件为例子,具体的流程如下所示:

深入理解Django的中间件middleware

中间件执行前提

中间件要按照一定的顺序一层一层的执行下去,需要按照标准返回特定的内容:

  • 如果为 None,则按照顺序继续向下执行
  • 如果为 HttpResonse 对象,则直接将这个对象返回给用户

此处有一个版本前后的区别,请大家注意区分:

在 Django1.10之后, 当某个中间件,例如CsrfViewMiddleware请求process_request没有返回 None 后,这个请求会交给CsrfViewMiddleware的process_response来返回,即返回给相同一层的中间件来返回:

深入理解Django的中间件middleware

在 Django1.10之前的版本,会返回到最底层的中间件来返回:

深入理解Django的中间件middleware

中间件方法:

1、process_request(self, request)

其中request参数就是我们的HttpRequest对象,process_request 会在每个request在被决定使用哪个view之前调用,它会返回None或HttpResponse对象

2、process_view(self, request, callback, callback_args, callback_kwargs)

其中request参数就是的HttpRequest对象,callback 就是请求被决定使用的 view 函数,书具体的函数名,不是字符串类型。callback_args和callback_kwargs是 view 函数需要接受的参数,它会返回None或HttpResponse对象

3、process_template_response(self, request, response)

其中request 是 HttpRequest 对象, response 是一个由Django view或者中间件返回的TemplateResponse 对象,process_template_response()在 view 使用 render 渲染一个模版对象完成之后被调用,它必须返回一个render 方法执行后的response对象。

4、process_exception(self, request, exception)

其中request参数就是的HttpRequest对象,exception是view函数中raise的Exception对象,当 view 函数 raise 一个 exception 的时候调用process_exception,它会返回None或HttpResponse对象

5、process_response(self, request, response)

其中request是 HttpRequest 对象,response 是一个django view或者中间件返回的 HttpResponse 或者StreamingHttpResponse对象,process_response会在所有响应到达浏览器之前被调用

中间件的详细执行流程

由于process_template_response在特定的 rander 渲染中才会被调用,所以过程中不添加该方法

深入理解Django的中间件middleware

自建中间件与执行过程测试

为了更加清晰的展示中间件的执行过程与如何自定义一个中间件,我们模拟一个简单的用户请求和中间件执行过程:

自定义中间件

from django.utils.deprecation import MiddlewareMixin
class MyMiddleware_1(MiddlewareMixin):
 def process_request(self, request):
  print("自定义 process_request 1")
  return None

 def process_response(self, request, response):
  print("自定义 process_response 1")
  return response

 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定义 process_view 1")
  return None

 def process_exception(self, request, exception):
  print("自定义 process_exception 1")


class MyMiddleware_2(MiddlewareMixin):

 def process_request(self, request):
  print("自定义 process_request 2")
  return None

 def process_response(self, request, response):
  print("自定义 process_response 2")
  return response

 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定义 process_view 2")
  return None

 def process_exception(self, request, exception):
  print("自定义 process_exception 2")

引入

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',
 'app01.middle_by_me.MyMiddleware_1', # 第一个自定义 middleware
 'app01.middle_by_me.MyMiddleware_2' # 第二个自定义 middleware
]

输出结果

深入理解Django的中间件middleware

自定义中间件应用场景

应用场景这个问题其实不是很好去固定,因为大家在实际使用过程中的需求都不尽相同,所以我简单的举个我可以想到的例子吧。

在不修改业务逻辑源代码的情况下,我可以使用中间件来对用户的访问进行一定的筛选过滤,或者访问控制。还有能想到的更加牛逼的操作是当源站的 CDN,请求穿透源站,middleware 判断请求的内容是否在缓存中,如果在缓存直接返回,而可以不经过业务后端逻辑,是不是很骚~

是不是很像一个所有视图函数的装饰器~~

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python 文件操作实现代码
Oct 07 Python
使用graphics.py实现2048小游戏
Mar 10 Python
Python实现设置windows桌面壁纸代码分享
Mar 28 Python
python中pass语句用法实例分析
Apr 30 Python
Python中对数组集进行按行打乱shuffle的方法
Nov 08 Python
超简单的Python HTTP服务
Jul 22 Python
详解python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
Aug 27 Python
python或C++读取指定文件夹下的所有图片
Aug 31 Python
解决Python数据可视化中文部分显示方块问题
May 16 Python
如何使用Django Admin管理后台导入CSV
Nov 06 Python
Python 删除List元素的三种方法remove、pop、del
Nov 16 Python
python3 删除所有自定义变量的操作
Apr 08 Python
python批量设置多个Excel文件页眉页脚的脚本
Mar 14 #Python
浅谈python正则的常用方法 覆盖范围70%以上
Mar 14 #Python
Python使用matplotlib绘制多个图形单独显示的方法示例
Mar 14 #Python
Python使用matplotlib绘制余弦的散点图示例
Mar 14 #Python
使用Python从零开始撸一个区块链
Mar 14 #Python
Python使用matplotlib绘图无法显示中文问题的解决方法
Mar 14 #Python
Django中url的反向查询的方法
Mar 14 #Python
You might like
PHP模块 Memcached功能多于Memcache
2011/06/14 PHP
PHP处理SQL脚本文件导入到MySQL的代码实例
2014/03/17 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
jQuery 1.3 和 Validation 验证插件1.5.1
2009/07/09 Javascript
jCallout 轻松实现气泡提示功能
2013/09/22 Javascript
JavaScript中的Function函数
2015/08/27 Javascript
JS鼠标拖拽实例分析
2015/11/23 Javascript
javascript实现数组去重的多种方法
2016/03/14 Javascript
详解Angular中$cacheFactory缓存的使用
2016/08/19 Javascript
jQuery文字轮播特效
2017/02/12 Javascript
详谈js中数组(array)和对象(object)的区别
2017/02/27 Javascript
js实现按座位号抽奖
2017/04/05 Javascript
对象不支持indexOf属性或方法的解决方法(必看)
2017/05/28 Javascript
AngularJS select设置默认值的实现方法
2017/08/25 Javascript
实例讲解javascript实现异步图片上传方法
2017/12/05 Javascript
vue 引入公共css文件的简单方法(推荐)
2018/01/20 Javascript
Bootbox将后台JSON数据填充Form表单的实例代码
2018/09/10 Javascript
vue component 中引入less文件报错 Module build failed
2019/04/17 Javascript
微信小程序获取用户信息及手机号(后端TP5.0)
2019/09/12 Javascript
浅谈layui使用模板引擎动态渲染元素要注意的问题
2019/09/14 Javascript
JavaScript中Object、map、weakmap的区别分析
2020/12/15 Javascript
python实现监控linux性能及进程消耗性能的方法
2014/07/25 Python
跟老齐学Python之编写类之一创建实例
2014/10/11 Python
在Python中处理XML的教程
2015/04/29 Python
Python中常见的数据类型小结
2015/08/29 Python
使用django-guardian实现django-admin的行级权限控制的方法
2018/10/30 Python
tesserocr与pytesseract模块的使用方法解析
2019/08/30 Python
css3新增颜色表示方式分享
2014/04/15 HTML / CSS
莱德杯高尔夫欧洲官方商店:Ryder Cup Shop
2019/08/14 全球购物
北京麒麟网信息技术有限公司网络游戏测试面试题
2013/09/28 面试题
土木工程应届生自荐信
2013/09/24 职场文书
争论的故事教学反思
2014/02/06 职场文书
自考毕业自我鉴定
2014/03/18 职场文书
依法行政工作汇报材料
2014/10/28 职场文书
学习党章的体会
2014/11/07 职场文书