何为AOP?
- AOP,面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等 。
AOP是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段
何为中间件?
- 中间件就是在目标和结果之间进行的额外处理过程,在Django中就是request和response之间进行的处理,相对来说实现起来比较简单,但是要注意它是对全局有效的,可以在全局范围内改变输入和输出结果
- 主要的功能是:登录认证、流量统计、恶意请求拦截等
如何在Django中自定义中间件?
这些是django自带的默认中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
我们首先在项目目录下创建一个名为middleware
的文件夹,然后在创建一个python文件,这里我把python文件命名为learnmiddle
from django.utils.deprecation import MiddlewareMixin
class HelloMiddle(MiddlewareMixin):
pass
基本的代码样式就是这个样子,然后有了这些之后在settings.py
自带的MIDDLEWARE
列表添加一条语句:
'middleware.learnmiddle.HelloMiddle',
把这个继承于MiddlewareMixin
的类注册上
django内置了五个切点接口:
- process_request:
在执行 视图函数之前 被调用,可不主动进行返回也可返回HttpResponse对象
def process_request(self, request):
pass
- process_views:
在执行 视图函数之前 被调用,可不主动进行返回也可返回HttpResponse对象
def process_views(self,request,view_func,view_args,view_kwargs):
pass
- process_template_response:
在 视图函数刚好执行完 后调用,必须返回response,且只在视图函数有render方法时被调用
def process_template_response(self,request,response)
pass
- process_response:
所有 响应返回浏览器之前 调用,必须返回response
def process_response(self,request,response)
pass
- process_exception
视图函数抛出异常时 调用,可不主动进行返回也可返回HttpResponse对象
这五个切点最常用的就是process_request
和process_exception
- 我们可以使用
process_request
实现:统计功能、黑白名单、反爬虫、限制访问频率
- 统计功能
我们可以使用统计功能记录用户的某些信息,然后进行数据分析,更好地利用市场
下面代码直接打印出了用户的主机地址
print(request.META.get('REMOTE_ADDR'))
- 黑白名单功能
一些购物网站可以对用户在网站上的某些举动对用户的信用等级进行评估,在某些抽奖活动上,为用户分别设置获奖概率,当然我们完全可以将这个功能写在视图函数上,但这样子会导致视图函数耦合性降低,降低代码阅读性,下面代码表示某个地址的用户无法进行抢票
if request.path == '/getticket/':
if ip.startswith('127.0.0.1'):
return HttpResponse('已抢光')
这个是自定义中间件中process_request
中的代码
def getticket(request):
return HttpResponse('优惠券还有')
这个是视图函数中的代码
- 可以看出:普通用户登录抽象页面时看到的是 ‘优惠券还有’
而以 127.0.0.1 开头的用户则只能看到已抢光
- 反爬虫功能
有些用户会对浏览器进行爬虫操作,如果一个用户对服务器进行频繁刷新爬取数据,那么对我们服务器资源的消耗将会是巨大的,不利于我们服务器的长期使用,下面代码展示了用户在十秒内只能对浏览器搜索一次
if request.path == '/fanpa/':
result = cache.get('ip')
if result:
return HttpResponse('您的访问过于频繁')
cache.set('ip',ip,timeout=10)
这个是自定义中间件中process_request
中的代码
def fanpa(request):
return HttpResponse('搜索成功')
这是视图函数中的代码
- 可以看到,如果我们进行正常操作,十秒内不过多对服务器发送请求,那么我们看到的就是 ‘搜索成功’ 的字样,如果我们十秒内向服务器发送请求超过一次,也就是把缓存过期时间设置为十秒,如果发送请求的时候缓存存在,那么我们就会看到 ‘您的访问过于频繁’ 地字样
- 限制访问频率
有些用户会对浏览器进行恶意操作,频繁刷新浏览器对服务器的负担很大,我们需要限制访问频率,下面代码展示了用户在六十秒之内只能访问十次,如果超过十次就得等待一定的时间才能进行操作,如果超过三十次,就讲用户拉入黑名单,禁封一天
#get一个黑名单缓存,如果存在则获取,如果不存在就新建一个[]空列表
black_list = cache.get('black', [])
#如果用户ip在黑名单内,则返回
if ip in black_list:
return HttpResponse('黑名单')
'''
在这里我们创建一个请求序列[]
每一次访问生成一个缓存期限为60秒的时间戳,把时间戳放进序列最前面
如果最前面的时间戳和最后面的时间戳的时间间隔大于60秒
我们就把最后那个扔掉,否则我们就把时间戳插在最前面
求出现在这个名为requests的序列的长度
如果长度大于10,返回请求次数过于频繁
如果长度大于30,拉进黑名单
'''
requests = cache.get('ip', []) #cache.get(参数一,参数二),当参数一不存在时返回参数二
while requests and time.time() - requests[-1] > 60:
requests.pop() #把尾部数据扔掉
# 插入requests序列的值为一段时间戳
requests.insert(0, time.time()) # 往前插入值
cache.set('ip', requests, timeout=60)
if len(requests) > 30:
black_list.append(ip)
cache.set('black',black_list,timeout=60*60*24) #进入,黑名单封一天
return HttpResponse('封一天')
if len(requests) > 10:
return HttpResponse('请求次数过于频繁')
- 我们可以使用
process_exception
实现当服务器抛出异常时,客户端不会直接报错,使某些功能仍然可以正常使用
有时候我们不想被用户看到某些报错页面,我们就可以在报错的时候拦截下来,返回某个正常页面
def process_exception(self,request,exception):
return redirect(reverse('shouye'))
这个代码表示当出现异常的时候直接返回首页