Django中间件工作流程及写法实例代码


Posted in Python onFebruary 06, 2018

熟悉web开发的同学对hook钩子肯定不陌生,通过钩子可以方便的实现一些触发和回调,并且做一些过滤和拦截。

django中的中间件(middleware)就是类似钩子的一种存在。下面我们来介绍一下,并且给出一些实例。

1、Middleware的工作流程

Django中间件工作流程及写法实例代码

我盗了一个图,看网上很多人用这个图,来源已经追不明白了。简单声明一下,这个图不是我的。看着图我们分析一下:

1)django的请求相应流程:HttpRequest -> RequestMiddleware -> view function -> ResponseMiddleware -> HttpResponse

可以看到一个请求到响应的过程,中间夹着两个middleware流程,请求中间件和响应中间件。

也就是说,django提供了一种机制,在:

  1. 请求到达视图函数中间
  2. 视图函数到响应之间

支持嵌入钩子。

这种钩子的特点:

  1. 全局,一旦你使用了中间件,并且发布生效的话,所有的请求都会经过你嵌入的中间件。
  2. 性能敏感,如果你的中间件性能差的话,那么会影响服务的整体性能。

2) django的middleware包含四个钩子函数:process_request/process_view/process_response/process_exception

process_request:接受request之后确定所执行的view之前

process_view:确定了所要执行的view之后,view真正执行之前

process_response:view执行之后

process_exceptionview:view执行抛出异常

而插入middleware的过程是在settings.py中配置,如下默认配置,我只截取了两个中间件:SessionMiddleware和CommonMiddleware。

MIDDLEWARE_CLASSES = (
  'django.contrib.sessions.middleware.SessionMiddleware',
  'django.middleware.common.CommonMiddleware',
  
  ...    
)

我们简单看一下SessionMiddleware的实现

import time
from importlib import import_module

from django.conf import settings
from django.utils.cache import patch_vary_headers
from django.utils.http import cookie_date


class SessionMiddleware(object):
  def __init__(self):
    engine = import_module(settings.SESSION_ENGINE)
    self.SessionStore = engine.SessionStore

  def process_request(self, request):
    session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
    request.session = self.SessionStore(session_key)

  def process_response(self, request, response):
    """
    If request.session was modified, or if the configuration is to save the
    session every time, save the changes and set a session cookie or delete
    the session cookie if the session has been emptied.
    """
    try:
      accessed = request.session.accessed
      modified = request.session.modified
      empty = request.session.is_empty()
    except AttributeError:
      pass
    else:
      # First check if we need to delete this cookie.
      # The session should be deleted only if the session is entirely empty
      if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
        response.delete_cookie(settings.SESSION_COOKIE_NAME)
      else:
        if accessed:
          patch_vary_headers(response, ('Cookie',))
        if modified or settings.SESSION_SAVE_EVERY_REQUEST:
          if request.session.get_expire_at_browser_close():
            max_age = None
            expires = None
          else:
            max_age = request.session.get_expiry_age()
            expires_time = time.time() + max_age
            expires = cookie_date(expires_time)
          # Save the session data and refresh the client cookie.
          # Skip session save for 500 responses, refs #3881.
          if response.status_code != 500:
            request.session.save()
            response.set_cookie(settings.SESSION_COOKIE_NAME,
                request.session.session_key, max_age=max_age,
                expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
                path=settings.SESSION_COOKIE_PATH,
                secure=settings.SESSION_COOKIE_SECURE or None,
                httponly=settings.SESSION_COOKIE_HTTPONLY or None)
    return response

可以看到在SessionMiddleware中默认只实现了process_requestprocess_response两个hook函数。

我们就以这个例子说明一下一个请求的执行过程。我们假设场景是这样的:

1)从上而下配置了两个Middleware(注意顺序):SessionMiddleware和CommonMiddleware

2)每个Middleware中的四个钩子函数齐全process_request/process_view/process_response/process_exception

执行顺序应该是这样的:

1、HttpRequest

2、SessionMiddleware process_request

3、SessionMiddleware process_view

4、CommonMiddleware process_request

5、CommonMiddleware process_view

6、view

7、CommonMiddleware process_response

8、CommonMiddleware process_exception(如有必要)

9、SessionMiddleware process_response

10、SessionMiddleware process_exception(如有必要)

11、HttpResponse

2、Middleware的写法

Middleware的写法很简单:

1)实现一个类,继承object就行;

2)重写其中的四个钩子函数就可以了。

这里要着重说一个常用的功能。

拦截器/过滤器(filter)

一般来说,每一个请求都要经过process_request这个钩子函数。你的实现中,函数的执行结果必然有两种(你要自己做异常处理):

1)None

2)HttpResponse 对象

如果返回None,请求流程继续执行,也就是继续进入其他的Middleware或者钩子函数。

如果返回HttpResponse对象,那么就直接返回到页面。通过这个功能我们可以做黑名单。

给一个例子:

就是统计pv

# -*- coding:utf-8 -*-
from datetime import datetime
from data_monitor.utils.dbmanager import MysqlManager
from data_monitor.common.constant import MYSQL_JOBS as mysql_config

class RequestHookMiddleware(object):

  def process_request(self, request):
    try:
      username = request.COOKIES.get('username')
      uri = request.path
      timestamp = str(datetime.now())
      db_obj = MysqlManager(
        mysql_config.get('host'),
        mysql_config.get('port'),
        mysql_config.get('db'),
        mysql_config.get('user'),
        mysql_config.get('password'),
        format=True,
      )
      field_str = 'username, uri, timestamp'
      value_str = '"%s","%s","%s"' % (username, uri, timestamp)
      db_obj.insert('pv', field_str, value_str)
      db_obj.close()
      return
    except Exception, ex:
      return

总结

以上就是本文关于Django中间件工作流程及写法实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
解决PyCharm中光标变粗的问题
Aug 05 Python
在pycharm中python切换解释器失败的解决方法
Oct 29 Python
django+mysql的使用示例
Nov 23 Python
django admin组件使用方法详解
Jul 19 Python
Python for循环及基础用法详解
Nov 08 Python
python科学计算之numpy——ufunc函数用法
Nov 25 Python
从训练好的tensorflow模型中打印训练变量实例
Jan 20 Python
Pyspark获取并处理RDD数据代码实例
Mar 27 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
Jun 04 Python
python实现图像外边界跟踪操作
Jul 13 Python
Python大批量搜索引擎图像爬虫工具详解
Nov 16 Python
Python 微信公众号文章爬取的示例代码
Nov 30 Python
Django数据库表反向生成实例解析
Feb 06 #Python
Python使用functools实现注解同步方法
Feb 06 #Python
django中send_mail功能实现详解
Feb 06 #Python
Python打印“菱形”星号代码方法
Feb 05 #Python
Django权限机制实现代码详解
Feb 05 #Python
Django中的Signal代码详解
Feb 05 #Python
Python实现XML文件解析的示例代码
Feb 05 #Python
You might like
php读取EXCEL文件 php excelreader读取excel文件
2012/12/06 PHP
php批量更改数据库表前缀实现方法
2013/10/26 PHP
php导入excel文件到mysql数据库的方法
2015/01/14 PHP
php实现改变图片直接打开为下载的方法
2015/04/14 PHP
php实现文本数据导入SQL SERVER
2015/05/17 PHP
PHP二维关联数组的遍历方式(实例讲解)
2017/10/18 PHP
PHP各种常见经典算法总结【排序、查找、翻转等】
2019/08/05 PHP
js中的window.open返回object的错误的解决方法
2009/08/15 Javascript
JS OOP包机制,类创建的方法定义
2009/11/02 Javascript
使用JS 清空File控件的路径值
2013/07/08 Javascript
jQuery中[attribute!=value]选择器用法实例
2014/12/31 Javascript
js实现遮罩层弹出框的方法
2015/01/15 Javascript
jquery中ready()函数执行的时机和window的load事件比较
2015/06/22 Javascript
JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件
2015/12/20 Javascript
全面解析JavaScript中的valueOf与toString方法(推荐)
2016/06/14 Javascript
JavaScript省市区三级联动菜单效果
2016/09/21 Javascript
bootstrap模态框实现拖拽效果
2016/12/14 Javascript
Node.js发送HTTP客户端请求并显示响应结果的方法示例
2017/04/12 Javascript
jquery.form.js异步提交表单详解
2017/04/25 jQuery
vue 中自定义指令改变data中的值
2017/06/02 Javascript
vue子父组件通信的实现代码
2017/07/09 Javascript
node.js-v6新版安装具体步骤(分享)
2017/09/06 Javascript
详解wow.js中各种特效对应的类名
2017/09/13 Javascript
vue项目在线上服务器访问失败原因分析
2020/08/14 Javascript
Python Requests 基础入门
2016/04/07 Python
Python即时网络爬虫项目启动说明详解
2018/02/23 Python
python Opencv将图片转为字符画
2021/02/19 Python
python+PyQT实现系统桌面时钟
2020/06/16 Python
浅谈pyqt5在QMainWindow中布局的问题
2019/06/21 Python
python实现将列表中各个值快速赋值给多个变量
2020/04/02 Python
简单了解Python变量作用域正确使用方法
2020/06/12 Python
微软加拿大官方网站:Microsoft Canada
2019/04/28 全球购物
简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程
2012/04/17 面试题
Linux Interview Questions For software testers
2012/06/02 面试题
离婚协议书范文2015
2015/01/26 职场文书
2019入党申请书范文3篇
2019/08/21 职场文书