详解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实现删除文件但保留指定文件
Jun 21 Python
python使用MySQLdb访问mysql数据库的方法
Aug 03 Python
json跨域调用python的方法详解
Jan 11 Python
python如何读写csv数据
Mar 21 Python
3个用于数据科学的顶级Python库
Sep 29 Python
浅谈python3.6的tkinter运行问题
Feb 22 Python
Python Django框架单元测试之文件上传测试示例
May 17 Python
Python合并2个字典成1个新字典的方法(9种)
Dec 19 Python
浅谈Python3实现两个矩形的交并比(IoU)
Jan 18 Python
基于Python数据分析之pandas统计分析
Mar 03 Python
解决Python 异常TypeError: cannot concatenate 'str' and 'int' objects
Apr 08 Python
Python使用matplotlib绘制圆形代码实例
May 27 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数组函数序列之prev() - 移动数组内部指针到上一个元素的位置,并返回该元素值
2011/10/31 PHP
解决PHP4.0 和 PHP5.0类构造函数的兼容问题
2013/08/01 PHP
phpexcel导入excel数据使用方法实例
2013/12/24 PHP
Google Map Api和GOOGLE Search Api整合实现代码
2009/07/18 Javascript
javascript 添加和移除函数的通用方法
2009/10/20 Javascript
一个XML格式数据转换为图表的例子
2010/02/09 Javascript
纯js实现背景图片切换效果代码
2010/11/14 Javascript
js中设置元素class的三种方法小结
2011/08/28 Javascript
js中的cookie的读写操作示例详解
2014/04/17 Javascript
jQuery简单动画变换效果实例分析
2016/07/04 Javascript
深入浅析JavaScript函数前面的加号和叹号
2016/07/09 Javascript
jQuery异步提交表单的两种方式
2016/09/13 Javascript
理解 Node.js 事件驱动机制的原理
2017/08/16 Javascript
JS运动特效之完美运动框架实例分析
2018/01/24 Javascript
详解使用React进行组件库开发
2018/02/06 Javascript
JavaScript模板引擎原理与用法详解
2018/12/24 Javascript
Vue实现远程获取路由与页面刷新导致404错误的解决
2019/01/31 Javascript
使用typescript改造koa开发框架的实现
2020/02/04 Javascript
基于VSCode调试网页JavaScript代码过程详解
2020/07/20 Javascript
Python简单格式化时间的方法【strftime函数】
2016/09/18 Python
python pandas 组内排序、单组排序、标号的实例
2018/04/12 Python
Tensorflow 训练自己的数据集将数据直接导入到内存
2018/06/19 Python
Python Django 实现简单注册功能过程详解
2019/07/29 Python
python ctypes库2_指定参数类型和返回类型详解
2019/11/19 Python
python GUI库图形界面开发之PyQt5信号与槽基本操作
2020/02/25 Python
15款Python编辑器的优缺点,别再问我“选什么编辑器”啦
2020/10/19 Python
高清屏下canvas重置尺寸引发的问题的解决
2019/10/14 HTML / CSS
房屋继承公证书
2014/04/10 职场文书
公司授权委托书范文
2014/08/02 职场文书
财务工作检讨书
2014/10/29 职场文书
优秀党员推荐材料
2014/12/18 职场文书
拾金不昧感谢信
2015/01/21 职场文书
工作收入证明模板
2015/06/12 职场文书
Angular性能优化之第三方组件和懒加载技术
2021/05/10 Javascript
python基础入门之普通操作与函数(三)
2021/06/13 Python
详解Android中的TimePickerView(时间选择器)的用法
2022/04/30 Java/Android