详解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 import自定义模块方法
Feb 12 Python
python创建一个最简单http webserver服务器的方法
May 08 Python
Python简单计算文件夹大小的方法
Jul 14 Python
浅析AST抽象语法树及Python代码实现
Jun 06 Python
Python深入06——python的内存管理详解
Dec 07 Python
使用Python的package机制如何简化utils包设计详解
Dec 11 Python
基于python 爬虫爬到含空格的url的处理方法
May 11 Python
Python学习笔记之函数的参数和返回值的使用
Nov 20 Python
使用Python实现分别输出每个数组
Dec 06 Python
Python使用jpype模块调用jar包过程解析
Jul 29 Python
python 实现socket服务端并发的四种方式
Dec 14 Python
浅谈pytorch中stack和cat的及to_tensor的坑
May 20 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
dede3.1分页文字采集过滤规则详说(图文教程)
2007/04/03 PHP
PHP中判断变量为空的几种方法分享
2013/08/26 PHP
PHP函数microtime()用法与说明
2013/12/04 PHP
iOS10推送通知开发教程
2016/09/19 PHP
JS动画效果代码3
2008/04/03 Javascript
JavaScript学习历程和心得小结
2010/08/16 Javascript
jQuery控制li上下循环滚动插件用法实例(附demo源码下载)
2016/05/28 Javascript
JS实现的JSON数组去重算法示例
2018/04/11 Javascript
JS使用Date对象实时显示当前系统时间简单示例
2018/08/23 Javascript
element-ui中Table表格省市区合并单元格的方法实现
2019/08/07 Javascript
Vue插件之滑动验证码
2019/09/21 Javascript
原生js实现随机点名功能
2019/11/05 Javascript
VUE 实现动态给对象增加属性,并触发视图更新操作示例
2019/11/29 Javascript
vue样式穿透 ::v-deep的具体使用
2020/06/04 Javascript
[08:47]2018国际邀请赛 OG战队举杯时刻
2018/08/29 DOTA
50行代码实现贪吃蛇(具体思路及代码)
2013/04/27 Python
python中pygame模块用法实例
2014/10/09 Python
详解Python的Django框架中的模版继承
2015/07/16 Python
对Python 获取类的成员变量及临时变量的方法详解
2019/01/22 Python
Python3实现计算两个数组的交集算法示例
2019/04/03 Python
解决pandas展示数据输出时列名不能对齐的问题
2019/11/18 Python
50行Python代码实现视频中物体颜色识别和跟踪(必须以红色为例)
2019/11/20 Python
Python 静态方法和类方法实例分析
2019/11/21 Python
python输出数组中指定元素的所有索引示例
2019/12/06 Python
纽约州一群才华横溢的金匠制作而成:Hearth Jewelry
2019/03/22 全球购物
美体小铺印度官网:The Body Shop印度
2019/10/17 全球购物
Unix/Linux开发面试题
2016/08/16 面试题
商务日语毕业生自荐信范文
2013/11/14 职场文书
奥巴马演讲稿
2014/01/08 职场文书
幼儿园毕业园长感言
2014/02/24 职场文书
党员干部公开承诺书
2014/03/26 职场文书
教师党员自我剖析材料
2014/09/29 职场文书
房产分割协议书范文
2014/11/21 职场文书
趣味运动会简讯
2015/07/20 职场文书
《棉鞋里的阳光》教学反思
2016/02/20 职场文书
MySQL官方导出工具mysqlpump的使用
2021/05/21 MySQL