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 相关文章推荐
Python中关键字is与==的区别简述
Jul 31 Python
在GitHub Pages上使用Pelican搭建博客的教程
Apr 25 Python
Python易忽视知识点小结
May 25 Python
Python3实现Web网页图片下载
Jan 28 Python
利用Python循环(包括while&for)各种打印九九乘法表的实例
Nov 06 Python
python3 pandas 读取MySQL数据和插入的实例
Apr 20 Python
python pandas中对Series数据进行轴向连接的实例
Jun 08 Python
Python常用的json标准库
Feb 19 Python
wxPython之wx.DC绘制形状
Nov 19 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
Mar 18 Python
Python使用socket模块实现简单tcp通信
Aug 18 Python
Python 调用C++封装的进一步探索交流
Mar 04 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超牛逼无限极分类生成树方法
2015/05/11 PHP
php使用array_search函数实现数组查找的方法
2015/06/12 PHP
php冒泡排序与快速排序实例详解
2015/12/07 PHP
php实现HTML实体编号与非ASCII字符串相互转换类实例
2016/11/02 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
2017/11/14 PHP
JavaScript indexOf方法入门实例(计算指定字符在字符串中首次出现的位置)
2014/10/17 Javascript
JavaScript精炼之构造函数 Constructor及Constructor属性详解
2015/11/05 Javascript
jQuery EasyUI 获取tabs的实例解析
2016/12/06 Javascript
vue+springboot实现项目的CORS跨域请求
2018/09/05 Javascript
vue-router 前端路由之路由传值的方式详解
2019/04/30 Javascript
解决removeEventListener 无法清除监听的问题
2020/10/30 Javascript
介绍Python的Urllib库的一些高级用法
2015/04/30 Python
Python 使用SMTP发送邮件的代码小结
2016/09/21 Python
django框架如何集成celery进行开发
2017/05/24 Python
Python Xml文件添加字节属性的方法
2018/03/31 Python
Python wxPython库Core组件BoxSizer用法示例
2018/09/03 Python
CentOS 7 安装python3.7.1的方法及注意事项
2018/11/01 Python
更新修改后的Python模块方法
2019/03/03 Python
python根据txt文本批量创建文件夹
2020/12/08 Python
对Python 简单串口收发GUI界面的实例详解
2019/06/12 Python
使用Python刷淘宝喵币(低阶入门版)
2019/10/30 Python
Python异常继承关系和自定义异常实现代码实例
2020/02/20 Python
Python gevent协程切换实现详解
2020/09/14 Python
python如何实时获取tcpdump输出
2020/09/16 Python
python 使用xlsxwriter循环向excel中插入数据和图片的操作
2021/01/01 Python
德购商城:德国进口直邮商城
2017/06/13 全球购物
夏尔巴人登珠峰品牌:Sherpa Adventure Gear
2018/02/08 全球购物
澳洲女装时尚在线:Blue Bungalow
2018/05/05 全球购物
优质美利奴羊毛袜,不只是徒步旅行:Darn Tough Vermont
2018/11/05 全球购物
村党的群众路线教育实践活动总结材料
2014/10/31 职场文书
财务总监岗位职责范本
2015/04/03 职场文书
《珍珠鸟》教学反思
2016/02/16 职场文书
JavaScript 中for/of,for/in 的详细介绍
2021/11/17 Javascript
漫画「日和酱的要求是绝对的」第3卷封面公开
2022/03/21 日漫
Netty分布式客户端处理接入事件handle源码解析
2022/03/25 Java/Android
星际争霸:毕姥爷vs解冻03
2022/04/01 星际争霸