详解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获取指定网页上所有超链接的方法
Apr 04 Python
TensorFlow入门使用 tf.train.Saver()保存模型
Apr 24 Python
Python判断有效的数独算法示例
Feb 23 Python
详解如何减少python内存的消耗
Aug 09 Python
python图片二值化提高识别率代码实例
Aug 24 Python
numpy数组做图片拼接的实现(concatenate、vstack、hstack)
Nov 08 Python
解决Pycharm的项目目录突然消失的问题
Jan 20 Python
pandas数据拼接的实现示例
Apr 16 Python
解决Pycharm 中遇到Unresolved reference 'sklearn'的问题
Jul 13 Python
使用numpngw和matplotlib生成png动画的示例代码
Jan 24 Python
python munch库的使用解析
May 25 Python
python pygame入门教程
Jun 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
使PHP自定义函数返回多个值
2006/11/26 PHP
php数组函数序列之array_search()- 按元素值返回键名
2011/11/04 PHP
PHP7扩展开发之基于函数方式使用lib库的方法详解
2018/01/15 PHP
php把字符串指定字符分割成数组的方法
2018/03/12 PHP
兼容IE与firefox火狐的回车事件(js与jquery)
2010/10/20 Javascript
网页编辑器ckeditor和ckfinder配置步骤分享
2012/05/24 Javascript
JS实现在状态栏显示打字效果完整实例
2015/11/02 Javascript
JS实现的新浪微博大厅文字内容滚动效果代码
2015/11/05 Javascript
怎么引入(调用)一个JS文件
2016/05/26 Javascript
vue webpack实用技巧总结
2018/04/24 Javascript
Nginx设置为Node.js的前端服务器方法总结
2019/03/27 Javascript
Vue在chrome44偶现点击子元素事件无法冒泡的解决方法
2019/12/15 Javascript
JS实现动态无缝轮播
2020/01/11 Javascript
[01:07:22]2014 DOTA2华西杯精英邀请赛 5 24 DK VS VG加赛
2014/05/26 DOTA
[00:12]DAC2018 Miracle-站上中单舞台,他能否再写奇迹?
2018/04/06 DOTA
在阿里云服务器上配置CentOS+Nginx+Python+Flask环境
2016/06/18 Python
Python中用post、get方式提交数据的方法示例
2017/09/22 Python
pandas.DataFrame 根据条件新建列并赋值的方法
2018/04/08 Python
Python判断有效的数独算法示例
2019/02/23 Python
python gensim使用word2vec词向量处理中文语料的方法
2019/07/05 Python
详解centos7+django+python3+mysql+阿里云部署项目全流程
2019/11/15 Python
Tensorflow中tf.ConfigProto()的用法详解
2020/02/06 Python
浅谈python累加求和+奇偶数求和_break_continue
2020/02/25 Python
Python模块zipfile原理及使用方法详解
2020/08/04 Python
python接口自动化框架实战
2020/12/23 Python
小学信息技术教学反思
2014/02/10 职场文书
幼儿园新年寄语
2014/04/03 职场文书
本科生导师推荐信范文
2014/05/18 职场文书
教师工作能力自我评价
2015/03/04 职场文书
2015年社区环境卫生工作总结
2015/04/21 职场文书
学习经验交流会演讲稿
2015/11/02 职场文书
2016秋季校长开学典礼致辞
2015/11/26 职场文书
英语教学课后反思
2016/02/15 职场文书
2016年清明节期间群众祭祀活动工作总结
2016/04/01 职场文书
Vue.js 带下拉选项的输入框(Textbox with Dropdown)组件
2021/04/17 Vue.js
分析SQL窗口函数之取值窗口函数
2022/04/21 Oracle