详解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 13 Python
Python 转义字符详细介绍
Mar 21 Python
Python生成器generator用法示例
Aug 10 Python
解决Pycharm出现的部分快捷键无效问题
Oct 22 Python
Python字符串的全排列算法实例详解
Jan 07 Python
Python with用法:自动关闭文件进程
Jul 10 Python
Django框架视图函数设计示例
Jul 29 Python
opencv resize图片为正方形尺寸的实现方法
Dec 26 Python
Python计算机视觉里的IOU计算实例
Jan 17 Python
用Python实现Newton插值法
Apr 17 Python
django如何自定义manage.py管理命令
Apr 27 Python
用PYTHON去计算88键钢琴的琴键频率和音高
Apr 10 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导出MySQL数据到Excel文件(fputcsv)
2011/07/03 PHP
比较简单的百度网盘文件直链PHP代码
2013/03/24 PHP
回帖脱衣服的图片实现代码
2014/02/15 PHP
PHP中date与gmdate的区别及默认时区设置
2014/05/12 PHP
Yii不依赖Model的表单生成器用法实例
2014/12/04 PHP
php的debug相关函数用法示例
2016/07/11 PHP
Laravel 5.5官方推荐的Nginx配置学习教程
2017/10/06 PHP
js下将字符串当函数执行的方法
2011/07/13 Javascript
jQuery中判断一个元素是否为另一个元素的子元素(或者其本身)
2012/03/21 Javascript
div模拟滚动条效果示例代码
2013/10/16 Javascript
深入理解JQuery循环绑定事件
2016/06/02 Javascript
Web前端框架Angular4.0.0 正式版发布
2017/03/28 Javascript
判断“命令按钮”是否被鼠标单击详解
2019/07/31 Javascript
原生JavaScript实现贪吃蛇游戏
2020/11/04 Javascript
[02:28]DOTA2 2015国际邀请赛中国区预选赛首日现场百态
2015/05/26 DOTA
新手该如何学python怎么学好python?
2008/10/07 Python
使用Python脚本来获取Cisco设备信息的示例
2015/05/04 Python
python操作mongodb根据_id查询数据的实现方法
2015/05/20 Python
python正则表达式之作业计算器
2016/03/18 Python
Python脚本实现12306火车票查询系统
2016/09/30 Python
Python enumerate索引迭代代码解析
2018/01/19 Python
Python程序运行原理图文解析
2018/02/10 Python
python实现电脑自动关机
2018/06/20 Python
Python统计python文件中代码,注释及空白对应的行数示例【测试可用】
2018/07/25 Python
详解Python 正则表达式模块
2018/11/05 Python
Python设计模式之策略模式实例详解
2019/01/21 Python
numpy基础教程之np.linalg
2019/02/12 Python
Python在cmd上打印彩色文字实现过程详解
2019/08/07 Python
OSPREY LONDON官网:英国本土皮具品牌
2019/05/31 全球购物
周生生珠宝香港官网:Chow Sang Sang(香港及海外配送)
2019/09/05 全球购物
Java如何支持I18N?
2016/10/31 面试题
大学生求职信例文
2014/06/29 职场文书
承诺书范本大全
2015/05/04 职场文书
Python 如何将integer转化为罗马数(3999以内)
2021/06/05 Python
SQL Server远程连接的设置步骤(图文)
2022/03/23 SQL Server
OpenCV实现常见的四种图像几何变换
2022/04/01 Python