详解django自定义中间件处理
中间件是一个钩子框架,它们可以介入Django的请求和响应处理过程。它是一个轻量级、底层的插件系统,用于在全局修改Django的输入或输出。
每个中间件组件负责完成某个特定的功能
这里介绍的中间件方法适用于Django1.10以上
相关文件:djangomiddleware
Django基础中间件
django.utils.deprecation.py classMiddlewareMixin(object): def__init__(self,get_response=None): self.get_response=get_response super(MiddlewareMixin,self).__init__() def__call__(self,request): response=None ifhasattr(self,'process_request'): response=self.process_request(request) ifnotresponse: response=self.get_response(request) ifhasattr(self,'process_response'): response=self.process_response(request,response) returnresponse
以上为Django基础中间件源码,要习惯于看源码,上面的这段代码并不复杂,下面我们来一一解释。
def__init__(self,get_response=None): self.get_response=get_response super(MiddlewareMixin,self).__init__()
熟悉python类的都不陌生__init__方法,这里主要是一次性配置和初始化
def__call__(self,request): response=None ifhasattr(self,'process_request'): response=self.process_request(request) ifnotresponse: response=self.get_response(request) ifhasattr(self,'process_response'): response=self.process_response(request,response) returnresponse
__call__为每个请求/响应执行的代码
self.process_request(request)为每个请求到调用视图之前的操作,通常可以在这里做一些用户请求频率的控制。
self.get_response(request)为调用视图
self.process_response(request,response)为调用视图完成后的操作
自定义中间件
刚才了解了基础中间件,现在就开始编写我们自己的中间件。
通常我们回去继承基础中间件来实现自己的功能
fromdjango.utils.deprecationimportMiddlewareMixin classPermissionMiddlewareMixin(MiddlewareMixin): """ django中间件 """ defprocess_request(self,request): pass defprocess_response(self,request,response): returnresponse
如果你要在请求之前做处理,需要定义process_request()方法,去实现相关功能
如果你要在视图调用之后做处理,需要定义process_response()方法,去实现相关功能
:warning:注意定义process_response()方法一定要returnresponse
需要将你编写的中间件添加到settings中的MIDDLEWARE里
我这里写了一个通过中间件限制客户端请求频率,有兴趣的可以看一下
django中间件客户端请求频率限制
通过redislua脚本对客户端IP请求频率限制
#coding:utf-8
__author__='carey@akhack.com'
fromdjango.utils.deprecationimportMiddlewareMixin
fromdjango.http.responseimportHttpResponse
fromdjango_redisimportget_redis_connection
fromhashlibimportmd5
classRequestBlockMiddlewareMixin(MiddlewareMixin):
"""
django中间件客户端请求频率限制
"""
limit=4#单位时间内允许请求次数
expire=1#限制时间
cache="default"#获取djangocache
defprocess_request(self,request):
num=self.set_key(request)
ifnum>self.limit:
returnHttpResponse("请求频率过快,请稍后重试",status=503)
@staticmethod
defget_ident(request):
"""
IdentifythemachinemakingtherequestbyparsingHTTP_X_FORWARDED_FOR
ifpresentandnumberofproxiesis>0.Ifnotuseallof
HTTP_X_FORWARDED_FORifitisavailable,ifnotuseREMOTE_ADDR.
"""
NUM_PROXIES=1
xff=request.META.get('HTTP_X_FORWARDED_FOR')
remote_addr=request.META.get('REMOTE_ADDR')
num_proxies=NUM_PROXIES
ifnum_proxiesisnotNone:
ifnum_proxies==0orxffisNone:
returnremote_addr
addrs=xff.split(',')
client_addr=addrs[-min(num_proxies,len(addrs))]
returnclient_addr.strip()
return''.join(xff.split())ifxffelseremote_addr
defget_md5(self,request):
"""
获取IPmd5值
:paramrequest:
:return:
"""
ip_str=self.get_ident(request)
ip_md5=md5()
ip_md5.update(ip_str.encode("utf-8"))
returnip_md5.hexdigest()
defset_key(self,request):
"""
通过redislua脚本设置请求请求次数和限制时间
:paramrequest:
:return:限制时间内请求次数
"""
lua="""
localcurrent
current=redis.call("incr",KEYS[1])
iftonumber(current)==1then
redis.call("expire",KEYS[1],ARGV[1])
end
returntonumber(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)
returndata
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。