深入理解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 命令行参数sys.argv
Sep 06 Python
Python字符串拼接、截取及替换方法总结分析
Apr 13 Python
Python爬取三国演义的实现方法
Sep 12 Python
Python实现字典按照value进行排序的方法分析
Dec 23 Python
python获取命令行输入参数列表的实例代码
Jun 23 Python
Python爬虫实现抓取京东店铺信息及下载图片功能示例
Aug 07 Python
python调用c++ ctype list传数组或者返回数组的方法
Feb 13 Python
使用WingPro 7 设置Python路径的方法
Jul 24 Python
python实现猜数字游戏
Mar 25 Python
Python中import导入不同目录的模块方法详解
Feb 18 Python
Python气泡提示与标签的实现
Apr 01 Python
基于Python制作一副扑克牌过程详解
Oct 19 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 输出简单动态WAP页面
2009/06/09 PHP
destoon实现调用自增数字从1开始的方法
2014/08/21 PHP
11个PHPer必须要了解的编程规范
2014/09/22 PHP
PHP连接SQLServer2005的方法
2015/01/27 PHP
php目录拷贝实现方法
2015/07/10 PHP
PHP实现APP微信支付的实例讲解
2018/02/10 PHP
PHP实现的简单组词算法示例
2018/04/10 PHP
javascript编程起步(第四课)
2007/01/10 Javascript
写的htc的数据表格
2007/01/20 Javascript
JS Range HTML文档/文字内容选中、库及应用介绍
2011/05/12 Javascript
JQuery入门——用one()方法绑定事件处理函数(仅触发一次)
2013/02/05 Javascript
jquery下div 的resize事件示例代码
2014/03/09 Javascript
jQuery源码分析之jQuery中的循环技巧详解
2014/09/06 Javascript
JS导出PDF插件的方法(支持中文、图片使用路径)
2016/07/12 Javascript
jQuery Ajax Post 回调函数不执行问题的解决方法
2016/08/15 Javascript
jQuery中库的引用方法
2018/01/06 jQuery
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
2018/04/01 Javascript
js Array.slice的8种不同用法示例
2019/07/10 Javascript
python str与repr的区别
2013/03/23 Python
Python新手在作用域方面经常容易碰到的问题
2015/04/03 Python
python基于multiprocessing的多进程创建方法
2015/06/04 Python
Python爬虫包BeautifulSoup简介与安装(一)
2018/06/17 Python
python 调用钉钉机器人的方法
2019/02/20 Python
使用Python发现隐藏的wifi
2020/03/04 Python
基于python检查SSL证书到期情况代码实例
2020/04/04 Python
PyQt中使用QtSql连接MySql数据库的方法
2020/07/28 Python
Python连接Mysql进行增删改查的示例代码
2020/08/03 Python
Python模拟登录requests.Session应用详解
2020/11/17 Python
浅谈css3中的前缀
2016/07/20 HTML / CSS
几道数据库的面试题或笔试题
2014/05/31 面试题
银行存款证明样本
2014/01/17 职场文书
大学生优秀自荐信范文
2014/02/25 职场文书
租房协议书范文
2014/08/20 职场文书
会计主管岗位职责
2015/04/02 职场文书
保安辞职申请书应该怎么写?
2019/07/15 职场文书
经典励志格言:每日一句,让你每天充满能量
2019/08/16 职场文书