详解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命令行解析模块详解
Feb 01 Python
Python全排列操作实例分析
Jul 24 Python
Python测试网络连通性示例【基于ping】
Aug 03 Python
opencv设置采集视频分辨率方式
Dec 10 Python
Python 实现打印单词的菱形字符图案
Apr 12 Python
python实现批量转换图片为黑白
Jun 16 Python
使用Python项目生成所有依赖包的清单方式
Jul 13 Python
通过代码实例解析Pytest运行流程
Aug 20 Python
Python 创建守护进程的示例
Sep 29 Python
python中doctest库实例用法
Dec 31 Python
关于Numpy之repeat、tile的用法总结
Jun 02 Python
Python&Matlab实现樱花的绘制
Apr 07 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文件读写操作之文件写入代码
2011/01/13 PHP
PHP利用超级全局变量$_GET来接收表单数据的实例
2016/11/05 PHP
基于CI框架的微信网页授权库示例
2016/11/25 PHP
彻底搞懂JS无缝滚动代码
2007/01/03 Javascript
jquery触发a标签跳转事件示例代码
2013/07/21 Javascript
如何在父窗口中得知window.open()出的子窗口关闭事件
2013/10/15 Javascript
使用js实现按钮控制文本框加1减1应用于小时+分钟
2013/12/09 Javascript
让input框实现类似百度的搜索提示(基于jquery事件监听)
2014/01/31 Javascript
很全面的JavaScript常用功能汇总集合
2016/01/22 Javascript
Bootstrap模仿起筷首页效果
2016/05/09 Javascript
jQuery实现百度登录框的动态切换效果
2017/04/21 jQuery
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
使用yeoman构建angular应用的方法
2017/08/14 Javascript
简单谈谈关于Angular Cli打包的事
2017/09/05 Javascript
ReactJS实现表单的单选多选和反选的示例
2017/10/13 Javascript
详谈commonjs模块与es6模块的区别
2017/10/18 Javascript
Bootstrap标签页(Tab)插件切换echarts不显示问题的解决
2018/07/13 Javascript
详解js加减乘除精确计算
2019/03/19 Javascript
微信小程序遍历Echarts图表实现多个饼图
2019/04/25 Javascript
vue读取本地的excel文件并显示在网页上方法示例
2019/05/29 Javascript
jQuery位置选择器用法实例分析
2019/06/28 jQuery
layer 关闭指定弹出层的例子
2019/09/25 Javascript
Vue组件生命周期运行原理解析
2020/11/25 Vue.js
[39:18]完美世界DOTA2联赛PWL S3 Forest vs LBZS 第二场 12.17
2020/12/19 DOTA
详解Python当中的字符串和编码
2015/04/25 Python
python破解bilibili滑动验证码登录功能
2019/09/11 Python
Python迭代器iterator生成器generator使用解析
2019/10/24 Python
Jupyter Notebook的连接密码 token查询方式
2020/04/21 Python
CSS3绘制超炫的上下起伏波动进度加载动画
2016/04/21 HTML / CSS
同步和异步有何异同,在什么情况下分别使用他们?
2012/12/28 面试题
毕业学生推荐信
2013/12/01 职场文书
教师网络培训感言
2014/03/09 职场文书
2015年干部教育培训工作总结
2015/05/15 职场文书
公司开业致辞
2015/07/29 职场文书
python制作图形界面的2048游戏, 基于tkinter
2021/04/06 Python
mysqldump进行数据备份详解
2022/07/15 MySQL