详解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 相关文章推荐
win7上python2.7连接mysql数据库的方法
Jan 14 Python
解决使用pycharm提交代码时冲突之后文件丢失找回的方法
Aug 05 Python
python中协程实现TCP连接的实例分析
Oct 14 Python
python实现逐个读取txt字符并修改
Dec 24 Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 Python
python项目对接钉钉SDK的实现
Jul 15 Python
对python中的float除法和整除法的实例详解
Jul 20 Python
django 中的聚合函数,分组函数,F 查询,Q查询
Jul 25 Python
使用批处理脚本自动生成并上传NuGet包(操作方法)
Nov 19 Python
使用tqdm显示Python代码执行进度功能
Dec 08 Python
Python 下载Bing壁纸的示例
Sep 29 Python
解决pycharm不能自动保存在远程linux中的问题
Feb 06 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实现采集程序原理和简单示例代码
2007/03/18 PHP
PHPMailer邮件类利用smtp.163.com发送邮件方法
2008/09/11 PHP
PHP 显示客户端IP与服务器IP的代码
2010/10/12 PHP
php数字游戏 计算24算法
2012/06/10 PHP
php记录代码执行时间(实现代码)
2013/07/05 PHP
Zend Framework教程之Zend_Registry对象用法分析
2016/03/22 PHP
php nginx 实时输出的简单实现方法
2018/01/21 PHP
Nigma vs Alliance BO5 第三场2.14
2021/03/10 DOTA
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
javaScript函数中执行C#代码中的函数方法总结
2013/08/07 Javascript
JavaScript事件代理和委托详解
2016/04/08 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
React Native实现进度条弹框的示例代码
2017/07/17 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
2019/04/16 Javascript
jQuery实现的图片点击放大缩小功能案例
2020/01/02 jQuery
JavaScript实现简易聊天对话框(加滚动条)
2020/02/10 Javascript
JavaScript设计模式---单例模式详解【四种基本形式】
2020/05/16 Javascript
[51:32]Optic vs Serenity 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
python文件读写操作与linux shell变量命令交互执行的方法
2015/01/14 Python
Python对数据库操作
2016/03/28 Python
python tensorflow学习之识别单张图片的实现的示例
2018/02/09 Python
Python爬虫实现(伪)球迷速成
2018/06/10 Python
Python 添加文件注释和函数注释操作
2020/08/09 Python
HTML5移动端开发遇见的东西
2019/10/11 HTML / CSS
Mytheresa中国官网:德国时尚奢侈品商城
2017/08/04 全球购物
"引用"与多态的关系
2013/02/01 面试题
介绍一下Prototype的$()函数,$F()函数,$A()函数都是什么作用?
2014/03/05 面试题
应用电子专业学生的自我评价
2013/10/16 职场文书
年终总结会议主持词
2014/03/17 职场文书
广播体操口号
2014/06/18 职场文书
领导个人查摆剖析材料
2014/10/29 职场文书
主持稿开场白
2015/06/01 职场文书
浅谈Redis跟MySQL的双写问题解决方案
2022/02/24 Redis
一文教你快速生成MySQL数据库关系图
2022/06/28 Redis
Windows Server 2016服务器用户管理及远程授权图文教程
2022/08/14 Servers