中间件是一个钩子框架,它们可以介入 Django 的请求和响应处理过程。 它是一个轻量级、底层的 插件 系统,用于在 全局修改 Django 的输入或输出 。
每个中间件组件负责完成某个特定的功能
这里介绍的中间件方法适用于 Django1.10 以上
相关文件: django middleware
Django基础中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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基础中间件源码,要习惯于看源码,上面的这段代码并不复杂,下面我们来一一解释。
1
2
3
|
def __init__( self , get_response = None ):
self .get_response = get_response
super (MiddlewareMixin, self ).__init__()
|
熟悉 python 类的都不陌生 __init__ 方法, 这里主要是 一次性配置和初始化
1
2
3
4
5
6
7
8
9
|
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)
为调用视图完成后的操作
自定义中间件
刚才了解了基础中间件,现在就开始编写我们自己的中间件。
通常我们回去继承基础中间件来实现自己的功能
1
2
3
4
5
6
7
8
9
10
11
12
|
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请求频率限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# 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
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://carey.akhack.com/2018/11/20/django自定义中间件处理/