详解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 相关文章推荐
Linux系统上Nginx+Python的web.py与Django框架环境
Dec 25 Python
使用Python3 编写简单信用卡管理程序
Dec 21 Python
Python对数据进行插值和下采样的方法
Jul 03 Python
Python中使用logging和traceback模块记录日志和跟踪异常
Apr 09 Python
Python 50行爬虫抓取并处理图灵书目过程详解
Sep 20 Python
Python3 实现爬取网站下所有URL方式
Jan 16 Python
Pytest参数化parametrize使用代码实例
Feb 22 Python
python实现跨excel sheet复制代码实例
Mar 03 Python
在Django中自定义filter并在template中的使用详解
May 19 Python
Python用摘要算法生成token及检验token的示例代码
Dec 01 Python
matplotlib之pyplot模块坐标轴标签设置使用(xlabel()、ylabel())
Feb 22 Python
Python爬虫数据的分类及json数据使用小结
Mar 29 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分页函数
2006/07/08 PHP
php 移除数组重复元素的一点说明
2008/11/27 PHP
yii2中的rules 自定义验证规则详解
2016/04/19 PHP
php操作access数据库的方法详解
2017/02/22 PHP
CI(CodeIgniter)框架视图中加载视图的方法
2017/03/24 PHP
Laravel5框架自定义错误页面配置操作示例
2019/04/17 PHP
JavaScript Object的extend是一个常用的功能
2009/12/02 Javascript
jquery 检测元素是否存在的实例代码
2013/11/19 Javascript
javascript伸缩菜单栏实现代码分享
2015/11/12 Javascript
深入分析Javascript事件代理
2016/01/30 Javascript
JavaScript操作表单实例讲解(上)
2016/06/20 Javascript
easyui datagrid 大数据加载效率慢,优化解决方法(推荐)
2016/11/09 Javascript
Bootstrap Modal遮罩弹出层(完整版)
2016/11/21 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
2016/11/28 Javascript
javascript prototype原型详解(比较基础)
2016/12/26 Javascript
详解vue-cli下ESlint 配置说明
2018/09/03 Javascript
nodejs基础之多进程实例详解
2018/12/27 NodeJs
[01:06:32]DOTA2上海特级锦标赛D组资格赛#1 EG VS VP第一局
2016/02/28 DOTA
速记Python布尔值
2017/11/09 Python
python+splinter自动刷新抢票功能
2018/09/25 Python
Python 获取项目根路径的代码
2019/09/27 Python
Python编程快速上手——选择性拷贝操作案例分析
2020/02/28 Python
linux面试题参考答案(11)
2016/11/26 面试题
应届大学生简历中的自我评价
2014/01/15 职场文书
黄河象教学反思
2014/02/10 职场文书
党员公开承诺书
2014/03/25 职场文书
法语专业求职信
2014/07/20 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
领导班子对照检查剖析材料
2014/10/13 职场文书
2014年党务公开工作总结
2014/12/09 职场文书
初三学生语文考试作弊检讨书
2014/12/14 职场文书
感谢信怎么写
2015/01/21 职场文书
技术员个人工作总结
2015/03/03 职场文书
2015年教师节贺卡寄语
2015/03/24 职场文书
2015年党务公开工作总结
2015/05/19 职场文书
Springboot中如何自动转JSON输出
2022/06/16 Java/Android