详解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中DOM方法的动态性
Apr 11 Python
python写日志封装类实例
Jun 28 Python
Python用zip函数同时遍历多个迭代器示例详解
Nov 14 Python
Flask框架的学习指南之制作简单blog系统
Nov 20 Python
python3+PyQt5使用数据库窗口视图
Apr 24 Python
python编辑用户登入界面的实现代码
Jul 16 Python
对python中字典keys,values,items的使用详解
Feb 03 Python
PYQT5实现控制台显示功能的方法
Jun 25 Python
Pandas分组与排序的实现
Jul 23 Python
python主线程与子线程的结束顺序实例解析
Dec 17 Python
PyCharm+Miniconda3安装配置教程详解
Feb 16 Python
Python xlwings插入Excel图片的实现方法
Feb 26 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 Memcache 中实现消息队列
2009/11/24 PHP
PHP基础学习之流程控制的实现分析
2013/04/28 PHP
PHP判断上传文件类型的解决办法
2015/10/20 PHP
PHP + plupload.js实现多图上传并显示进度条加删除实例代码
2017/03/06 PHP
一个简单的js渐显(fadeIn)渐隐(fadeOut)类
2010/06/19 Javascript
js解析与序列化json数据(二)序列化探讨
2013/02/01 Javascript
JQuery获取或设置ckeditor的数据(示例代码)
2013/11/15 Javascript
深入理解JavaScript的React框架的原理
2015/07/02 Javascript
JavaScript模块规范之AMD规范和CMD规范
2015/10/27 Javascript
js绑定事件和解绑事件
2017/04/27 Javascript
vue-scroller记录滚动位置的示例代码
2018/01/17 Javascript
Express进阶之log4js实用入门指南
2018/02/10 Javascript
微信小程序canvas.drawImage完全显示图片问题的解决
2018/11/30 Javascript
如何让微信小程序页面之间的通信不再变困难
2019/06/03 Javascript
javascript设计模式 ? 策略模式原理与用法实例分析
2020/04/21 Javascript
jQuery 函数实例分析【函数声明、函数表达式、匿名函数等】
2020/05/19 jQuery
[53:21]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS LGD-CDEC
2014/05/22 DOTA
[54:15]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第二场2月1日
2021/03/11 DOTA
python连接sql server乱码的解决方法
2013/01/28 Python
python中__call__内置函数用法实例
2015/06/04 Python
python数据封装json格式数据
2018/03/04 Python
PythonWeb项目Django部署在Ubuntu18.04腾讯云主机上
2019/04/01 Python
基于python的itchat库实现微信聊天机器人(推荐)
2019/10/29 Python
python实现贪吃蛇游戏源码
2020/03/21 Python
Python plt 利用subplot 实现在一张画布同时画多张图
2021/02/26 Python
纯CSS3实现圆角效果(含IE兼容解决方法)
2014/05/07 HTML / CSS
一套Java笔试题
2016/08/20 面试题
解释下面关于J2EE的名词
2013/11/15 面试题
幼儿园母亲节活动总结
2015/02/10 职场文书
设备技术员岗位职责
2015/04/11 职场文书
2016年习主席讲话学习心得体会
2016/01/20 职场文书
MYSQL主从数据库同步备份配置的方法
2021/05/26 MySQL
python装饰器代码解析
2022/03/23 Python
Python Pandas解析读写 CSV 文件
2022/04/11 Python
Windows server 2012 配置Telnet以及用法详解
2022/04/28 Servers
Docker与K8s关系介绍不会Docker也可以使用K8s
2022/06/25 Servers