详解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是编译运行的验证方法
Jan 30 Python
python删除特定文件的方法
Jul 30 Python
python中异常捕获方法详解
Mar 03 Python
Python图像处理实现两幅图像合成一幅图像的方法【测试可用】
Jan 04 Python
对python中字典keys,values,items的使用详解
Feb 03 Python
python 实现将文件或文件夹用相对路径打包为 tar.gz 文件的方法
Jun 10 Python
Python使用正则表达式分割字符串的实现方法
Jul 16 Python
python3中eval函数用法使用简介
Aug 02 Python
python爬虫爬取幽默笑话网站
Oct 24 Python
Python实现新型冠状病毒传播模型及预测代码实例
Feb 05 Python
django inspectdb 操作已有数据库数据的使用步骤
Feb 07 Python
python 装饰器重要在哪
Feb 14 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函数
2008/10/03 PHP
php 无法加载mcrypt.dll的解决办法
2013/04/03 PHP
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
php中有关合并某一字段键值相同的数组合并的改进
2015/03/10 PHP
php实现的简单数据库操作Model类
2016/11/16 PHP
javascript实现仿银行密码输入框效果的代码
2007/12/13 Javascript
浅析Javascript中“==”与“===”的区别
2014/12/23 Javascript
JavaScript前补零操作实例
2015/03/11 Javascript
jQuery实现伸展与合拢panel的方法
2015/04/30 Javascript
Webpack 实现 Node.js 代码热替换
2015/10/22 Javascript
jQuery实现订单提交页发送短信功能前端处理方法
2016/07/04 Javascript
jQuery图片切换动画特效
2016/11/02 Javascript
jQuery给表格添加分页效果
2017/03/02 Javascript
Bootstrap如何激活导航状态
2017/03/22 Javascript
Vue中的v-for循环key属性注意事项小结
2018/08/12 Javascript
vue-cli监听组件加载完成的方法
2018/09/07 Javascript
微信公众号平台接口开发 获取access_token过程解析
2019/08/14 Javascript
vue.js的简单自动求和计算实例
2019/11/08 Javascript
Vue实现背景更换颜色操作
2020/07/17 Javascript
VUE UPLOAD 通过ACTION返回上传结果操作
2020/09/07 Javascript
[01:06:54]DOTA2-DPC中国联赛 正赛 RNG vs Dragon BO3 第一场 1月24日
2021/03/11 DOTA
详解Python的Flask框架中生成SECRET_KEY密钥的方法
2016/06/07 Python
使用Python对Csv文件操作实例代码
2017/05/12 Python
Python中定时任务框架APScheduler的快速入门指南
2017/07/06 Python
Python实现动态添加属性和方法操作示例
2018/07/25 Python
python实现扫描局域网指定网段ip的方法
2019/04/16 Python
鼠标滚轮事件和Mac触控板双指事件
2019/12/23 HTML / CSS
法国太阳镜店:Sunglasses Shop
2016/08/27 全球购物
iHerb香港:维生素、补充剂和天然保健品
2017/08/01 全球购物
澳洲小众品牌的集合网站:BNKR
2018/02/23 全球购物
竞聘副主任科员演讲稿
2014/01/11 职场文书
亮化工程实施方案
2014/03/17 职场文书
企业安全生产承诺书
2014/05/22 职场文书
优秀团员事迹材料2000字
2014/08/20 职场文书
个人房屋租赁合同(标准范本)
2019/09/16 职场文书
python中使用redis用法详解
2022/12/24 Redis