详解django自定义中间件处理


Posted in Python onNovember 21, 2018

中间件是一个钩子框架,它们可以介入 Django 的请求和响应处理过程。 它是一个轻量级、底层的 插件 系统,用于在 全局修改 Django 的输入或输出 。

每个中间件组件负责完成某个特定的功能

这里介绍的中间件方法适用于 Django1.10 以上

相关文件: django middleware

Django基础中间件

django.utils.deprecation.py

class MiddlewareMixin(object):
 def __init__(self, get_response=None):
  self.get_response = get_response
  super(MiddlewareMixin, self).__init__()

 def __call__(self, request):
  response = None
  if hasattr(self, 'process_request'):
   response = self.process_request(request)
  if not response:
   response = self.get_response(request)
  if hasattr(self, 'process_response'):
   response = self.process_response(request, response)
  return response

以上为Django基础中间件源码,要习惯于看源码,上面的这段代码并不复杂,下面我们来一一解释。

def __init__(self, get_response=None):
 self.get_response = get_response
 super(MiddlewareMixin, self).__init__()

熟悉 python 类的都不陌生 __init__ 方法, 这里主要是 一次性配置和初始化

def __call__(self, request):
  response = None
  if hasattr(self, 'process_request'):
    response = self.process_request(request)
  if not response:
    response = self.get_response(request)
  if hasattr(self, 'process_response'):
    response = self.process_response(request, response)
  return response

__call__ 为每个请求/响应执行的代码

self.process_request(request) 为每个请求到调用视图之前的操作,通常可以在这里做一些用户请求频率的控制。

self.get_response(request) 为调用视图

self.process_response(request, response) 为调用视图完成后的操作

自定义中间件

刚才了解了基础中间件,现在就开始编写我们自己的中间件。

通常我们回去继承基础中间件来实现自己的功能

from django.utils.deprecation import MiddlewareMixin

class PermissionMiddlewareMixin(MiddlewareMixin):
  """
  django 中间件
  """

  def process_request(self, request):
    pass

  def process_response(self, request, response):
    return response

如果你要在请求之前做处理,需要定义 process_request() 方法,去实现相关功能

如果你要在视图调用之后做处理,需要定义 process_response() 方法,去实现相关功能

:warning:注意 定义 process_response() 方法一定要 return response

需要将你编写的中间件添加到 settings 中的 MIDDLEWARE 里

我这里写了一个通过中间件限制客户端请求频率,有兴趣的可以看一下

django中间件客户端请求频率限制

通过redis lua脚本对客户端IP请求频率限制

# coding:utf-8

__author__ = 'carey@akhack.com'

from django.utils.deprecation import MiddlewareMixin
from django.http.response import HttpResponse
from django_redis import get_redis_connection
from hashlib import md5


class RequestBlockMiddlewareMixin(MiddlewareMixin):
  """
  django中间件客户端请求频率限制
  """

  limit = 4 # 单位时间内允许请求次数
  expire = 1 # 限制时间
  cache = "default" # 获取django cache

  def process_request(self, request):
    num = self.set_key(request)
    if num > self.limit:
      return HttpResponse("请求频率过快,请稍后重试", status=503)

  @staticmethod
  def get_ident(request):
    """
    Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
    if present and number of proxies is > 0. If not use all of
    HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
    """
    NUM_PROXIES = 1
    xff = request.META.get('HTTP_X_FORWARDED_FOR')
    remote_addr = request.META.get('REMOTE_ADDR')
    num_proxies = NUM_PROXIES

    if num_proxies is not None:
      if num_proxies == 0 or xff is None:
        return remote_addr
      addrs = xff.split(',')
      client_addr = addrs[-min(num_proxies, len(addrs))]
      return client_addr.strip()

    return ''.join(xff.split()) if xff else remote_addr

  def get_md5(self, request):
    """
    获取IP md5值
    :param request:
    :return:
    """
    ip_str = self.get_ident(request)
    ip_md5 = md5()
    ip_md5.update(ip_str.encode("utf-8"))
    return ip_md5.hexdigest()

  def set_key(self, request):
    """
    通过redis lua脚本设置请求请求次数和限制时间
    :param request:
    :return: 限制时间内请求次数
    """
    lua = """
      local current
      current = redis.call("incr",KEYS[1])
      if tonumber(current) == 1 then
        redis.call("expire",KEYS[1],ARGV[1])
      end
      return tonumber(redis.call("get", KEYS[1]))
      """
    key = self.get_md5(request)
    redis_cli = get_redis_connection(self.cache)
    data = redis_cli.eval(lua, 1, key, self.expire, self.limit)
    return data

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python迭代器和生成器介绍
Mar 06 Python
Python yield 使用浅析
May 28 Python
浅谈Python的垃圾回收机制
Dec 17 Python
Python中单例模式总结
Feb 20 Python
解决新django中的path不能使用正则表达式的问题
Dec 18 Python
django ajax发送post请求的两种方法
Jan 05 Python
python学生管理系统的实现
Apr 05 Python
使用python计算三角形的斜边例子
Apr 15 Python
Python爬虫实现百度翻译功能过程详解
May 29 Python
Python Selenium XPath根据文本内容查找元素的方法
Dec 07 Python
详解Python+Selenium+ChromeDriver的配置和问题解决
Jan 19 Python
python 详解turtle画爱心代码
Feb 15 Python
pygame游戏之旅 添加游戏界面按键图形
Nov 20 #Python
pygame游戏之旅 添加游戏介绍
Nov 20 #Python
pygame游戏之旅 计算游戏中躲过的障碍数量
Nov 20 #Python
pygame游戏之旅 添加碰撞效果的方法
Nov 20 #Python
pygame游戏之旅 如何制作游戏障碍
Nov 20 #Python
用Python编写一个简单的CS架构后门的方法
Nov 20 #Python
python pygame实现2048游戏
Nov 20 #Python
You might like
php获取用户IPv4或IPv6地址的代码
2012/11/15 PHP
php上传图片客户端和服务器端实现方法
2015/03/30 PHP
php获取数据库结果集方法(推荐)
2017/06/01 PHP
页面调用单个swf文件,嵌套出多个方法。
2011/11/21 Javascript
让新消息在网页标题闪烁提示的jQuery代码
2013/11/04 Javascript
Underscore.js 1.3.3 中文注释翻译说明
2015/06/25 Javascript
javascript实现检验的各种规则
2015/07/31 Javascript
快速实现jQuery多级菜单效果
2017/02/01 Javascript
利用n工具轻松管理Node.js的版本
2017/04/21 Javascript
JavaScript箭头函数_动力节点Java学院整理
2017/06/28 Javascript
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
2018/09/05 Javascript
Vue-CLI项目中路由传参的方式详解
2019/09/01 Javascript
[03:13]DOTA2-DPC中国联赛1月25日Recap集锦
2021/03/11 DOTA
Python定时执行之Timer用法示例
2015/05/27 Python
Python模拟鼠标点击实现方法(将通过实例自动化模拟在360浏览器中自动搜索python)
2017/08/23 Python
Python request设置HTTPS代理代码解析
2018/02/12 Python
PyCharm在新窗口打开项目的方法
2019/01/17 Python
在Python中字典根据多项规则排序的方法
2019/01/21 Python
python实现的爬取电影下载链接功能示例
2019/08/26 Python
pycharm部署、配置anaconda环境的教程
2020/03/24 Python
matplotlib jupyter notebook 图像可视化 plt show操作
2020/04/24 Python
python识别验证码的思路及解决方案
2020/09/13 Python
Python使用grequests并发发送请求的示例
2020/11/05 Python
windows+vscode安装paddleOCR运行环境的步骤
2020/11/11 Python
Kathmandu英国网站:新西兰户外运动品牌
2017/03/27 全球购物
linux下进程间通信的方式
2014/12/23 面试题
各营销点岗位职责范本
2014/03/05 职场文书
协议书范本
2014/04/23 职场文书
建筑工程技术专业求职信
2014/07/16 职场文书
个人三严三实对照检查材料思想汇报
2014/09/22 职场文书
教师自查自纠工作情况报告
2014/10/29 职场文书
2016年暑假学生家长评语
2015/12/01 职场文书
演讲稿之开卷有益
2019/08/07 职场文书
Java版 单机五子棋
2022/05/04 Java/Android
详解ZABBIX监控ESXI主机的问题
2022/06/21 Servers