详解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进行TCP网络编程的教程
Apr 29 Python
python基于Tkinter库实现简单文本编辑器实例
May 05 Python
在Python中操作列表之list.extend()方法的使用
May 20 Python
简介Python设计模式中的代理模式与模板方法模式编程
Feb 02 Python
python递归删除指定目录及其所有内容的方法
Jan 13 Python
django实现登录时候输入密码错误5次锁定用户十分钟
Nov 05 Python
Python中判断子串存在的性能比较及分析总结
Jun 23 Python
详解python和matlab的优势与区别
Jun 28 Python
使用PyInstaller将Pygame库编写的小游戏程序打包为exe文件及出现问题解决方法
Sep 06 Python
python能做哪些生活有趣的事情
Sep 09 Python
Pandas直接读取sql脚本的方法
Jan 21 Python
利用python实现汉诺塔游戏
Mar 01 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
Yii调试SQL的常用方法
2014/07/09 PHP
php简单实现多字节字符串翻转的方法
2015/03/31 PHP
WordPress中转义HTML与过滤链接的相关PHP函数使用解析
2015/12/22 PHP
PHP内存缓存功能memcached示例
2016/10/19 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
PHP curl 或 file_get_contents 获取需要授权页面的方法
2017/05/05 PHP
如何利用预加载优化Laravel Model查询详解
2017/08/11 PHP
网上应用的一个不错common.js脚本
2007/08/08 Javascript
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
2014/12/20 Javascript
JS设置网页图片vspace和hspace属性的方法
2015/04/01 Javascript
JavaScript资源预加载组件和滑屏组件的使用推荐
2016/03/10 Javascript
Bootstrap幻灯片轮播图支持触屏左右手势滑动的实现方法
2016/10/13 Javascript
详解Nodejs之静态资源处理
2017/06/05 NodeJs
jQueryeasyui 中如何使用datetimebox 取两个日期间相隔的天数
2017/06/13 jQuery
angular.js + require.js构建模块化单页面应用的方法步骤
2017/07/19 Javascript
深入学习js函数的隐式参数 arguments 和 this
2019/06/24 Javascript
layui(1.0.9)文件上传upload,前后端的实例代码
2019/09/26 Javascript
Vue如何使用混合Mixins和插件开发详解
2020/02/05 Javascript
[52:26]完美世界DOTA2联赛决赛 FTD vs Phoenix 第一场 11.08
2020/11/11 DOTA
python自动裁剪图像代码分享
2017/11/25 Python
python dataframe向下向上填充,fillna和ffill的方法
2018/11/28 Python
Python XML转Json之XML2Dict的使用方法
2019/01/15 Python
Python实现使用request模块下载图片demo示例
2019/05/24 Python
python 实现交换两个列表元素的位置示例
2019/06/26 Python
html5设计原理(推荐收藏)
2014/05/17 HTML / CSS
网络安全类面试题
2015/08/01 面试题
法律专业推荐信范文
2013/11/29 职场文书
高校辅导员推荐信范文
2013/12/25 职场文书
房地产销售计划书
2014/01/10 职场文书
黄河象教学反思
2014/02/10 职场文书
5.12护士节演讲稿
2014/04/30 职场文书
提拔干部考察材料
2014/05/26 职场文书
离婚协议书格式
2015/01/26 职场文书
银行求职自荐信范文
2015/03/04 职场文书
辩护词范文大全
2015/05/21 职场文书
Mysql多层子查询示例代码(收藏夹案例)
2022/03/31 MySQL