详解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上传文件和字符到PHP服务器
Nov 24 Python
《Python学习手册》学习总结
Jan 17 Python
详解python编译器和解释器的区别
Jun 24 Python
python函数参数(必须参数、可变参数、关键字参数)
Aug 16 Python
python+selenium select下拉选择框定位处理方法
Aug 24 Python
python字符串替换re.sub()实例解析
Feb 09 Python
浅谈tensorflow模型保存为pb的各种姿势
May 25 Python
python实现画图工具
Aug 27 Python
python logging模块的使用详解
Oct 23 Python
Python图像处理之膨胀与腐蚀的操作
Feb 07 Python
AI:如何训练机器学习的模型
Apr 16 Python
关于python pygame游戏进行声音添加的技巧
Oct 24 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中使用Oracle数据库(6)
2006/10/09 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
php使用curl并发减少后端访问时间的方法分析
2016/05/12 PHP
PHP第三方登录―QQ登录实现方法
2017/02/06 PHP
Laravel 5.5官方推荐的Nginx配置学习教程
2017/10/06 PHP
详解关于php的xdebug配置(编辑器vscode)
2019/01/29 PHP
JS window.opener返回父页面的应用
2009/10/24 Javascript
jquery photoFrame 图片边框美化显示插件
2010/06/28 Javascript
jQuery中的bind绑定事件与文本框改变事件的临时解决方法
2010/08/13 Javascript
javascript进行数组追加方法小结
2014/06/16 Javascript
jquery用data方法获取某个元素上的事件
2014/06/23 Javascript
express的中间件cookieParser详解
2014/12/04 Javascript
基于javascript实现判断移动终端浏览器版本信息
2014/12/09 Javascript
分享33个jQuery与CSS3实现的绚丽鼠标悬停效果
2014/12/15 Javascript
纯javascript实现的小游戏《Flappy Pig》实例
2015/07/27 Javascript
JS实现可调整倒计时间代码分享
2015/08/18 Javascript
jQuery on()绑定动态元素出现的问题小结
2016/02/19 Javascript
微信小程序 Tab页切换更新数据
2017/01/05 Javascript
Bootstrap页面缩小变形的快速解决办法
2017/02/03 Javascript
JavaScript中的工厂函数(推荐)
2017/03/08 Javascript
javascript 面向对象实战思想分享
2017/09/07 Javascript
禁止弹窗中蒙层底部页面跟随滚动的几种方法
2017/12/07 Javascript
[02:14]2016国际邀请赛中国区预选赛Ehome晋级之路
2016/07/01 DOTA
Python socket.error: [Errno 98] Address already in use的原因和解决方法
2014/08/25 Python
Python基于回溯法子集树模板解决旅行商问题(TSP)实例
2017/09/05 Python
Python之多线程爬虫抓取网页图片的示例代码
2018/01/10 Python
详解Python 协程的详细用法使用和例子
2018/06/15 Python
python实现俄罗斯方块游戏(改进版)
2020/03/13 Python
ALDI奥乐齐官方海外旗舰店:德国百年超市
2017/12/27 全球购物
数据库什么时候应该被重组
2012/11/02 面试题
英文自荐信
2013/12/15 职场文书
优秀学生干部推荐材料
2014/02/03 职场文书
协议书范本
2014/04/23 职场文书
村容村貌整治方案
2014/05/21 职场文书
部门经理迟到检讨书
2015/02/16 职场文书
借款民事起诉状范文
2015/05/19 职场文书