正在学习中间件,于是写了个Demo,这个Demo在runserver下中间件的运行是正常的,但部署到uWSGI后就无法正常统计ip每分钟的访问频率了,百度和谷歌后也没能找到解决我困惑的答案。
很简单的Demo
import time
from django.core.cache import cache
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class FindIPMiddleware(MiddlewareMixin, SaveIP):
def process_request(self, request):
ip = request.META.get('REMOTE_ADDR')
black_list = cache.get('black', []) # 如果cache中没有black,就返回一个空列表
if ip in black_list:
return HttpResponse('此ip因多次违规,已被禁止访问')
# 将每次指定ip访问的时间记录在requests中
requests = cache.get(ip, [])
# 为了测试是否与uWSGI的多线程和多进程有关,将每次访问的requests记录在test.txt中
with open('test.txt', 'a') as f:
f.write(str(requests)+'\n')
# 如果requests存在且当前时间与最早访问的时间差大于60秒,就pop掉
while requests and time.time() - requests[-1] > 60:
requests.pop()
# 将当前访问的时间插入为requests列表的第一个
requests.insert(0, time.time())
# 将ip-requests放到缓存中
cache.set(ip, requests, timeout=60)
# 如果requets长度大于30,封禁ip,大于等于10小于30警告
if len(requests) > 30:
black_list.append(ip)
cache.set('black', black_list, timeout=60*60*24)
return HttpResponse('ip被封禁')
if len(requests) >= 10:
return HttpResponse('请求频率过高,已被限制访问,如果继续恶意访问,将被添加进黑名单')
return None
开发环境与线上环境分别访问10次,生成两个text.txt文件
runserver开发服务器下生成的test.txt文件:
[]
[1574515435.201666]
[1574515436.6527722, 1574515435.201666]
[1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515438.856246, 1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515439.553581, 1574515438.856246, 1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515440.3515499, 1574515439.553581, 1574515438.856246, 1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515441.155905, 1574515440.3515499, 1574515439.553581, 1574515438.856246, 1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
[1574515441.787576, 1574515441.155905, 1574515440.3515499, 1574515439.553581, 1574515438.856246, 1574515438.1917062, 1574515437.4844859, 1574515436.6527722, 1574515435.201666]
这是线上环境生成的test.txt文件:
[]
[]
[]
[]
[1574516234.4257581]
[1574516232.7529194]
[1574516233.7064342]
[1574516235.0543022]
[1574516237.4400864, 1574516235.0543022]
[1574516236.268929, 1574516232.7529194]
这是uWSGI.ini配置文件:
[uwsgi]
http=0.0.0.0:8888
chdir=/home/thepoy/django/javaScript
wsgi-file=javaScript/wsgi.py
processes=4
threads=2
enable-threads=True
master=True
pidfile=uwsgi.pid
daemonize=uwsgi.log
开发text.txt文件的记录是逐条增加的,
但是线上text.txt文件却非如此,这样就无法正常统计ip每分钟的访问频率了。
个人觉得出现这个问题应该是与uWSGI的多进程和多线程有关,但是这不要紧,我想知道怎么才能解决这个问题,请各位大佬们指点一下,谢谢!
已解决:
此问题确实是因为uWSGI的多进程引起的,具体原因就是每个进程的django的cache不共享,每次访问时无法获取其他进程中的cache。
所以在多进程中,不宜使用cache进行ip访问频率的统计,可以用session(默认session就是个表)或数据库