1. Python

Django-中间件

!!这篇本来是在本地用Markdown语法写的;结果wordpress对md的资瓷没有我想象中好。只好再把本地的md改一改手动移过来!

一.中间件应用

  • 实现统计功能

    • 统计 IP

    • 统计浏览器

  • 实现权重控制

    • 黑名单

    • 白名单

  • 实现反爬

    • 反爬虫

      • 十秒之内只能搜索一次

    • 实现频率控制

      • 六十秒内只能访问十次

  • 界面友好化

  • 应用交互友好化

    • 服务器500错误处理

对于上面的应用场景,下面选择反爬虫和频率控制进行实现

1.1反爬虫实现

这次我们还是从路由写起,在polls这个app的路由器urls.py的urlpatterns中添加如下内容

path('bittorrent', views.bittorrent, name='bittorrent'),

这样我们就写了一个种子页面用来模拟种子搜索。

接下来去polls这个app的views.py中编写对应的视图函数

def bittorrent():
    return HttpResponse("<h1>全网种子搜索</h1>")

简单一点就直接返回一句话吧

然后开始编写中间件部分(编写自己的中间件)

  • 在工程目录下创建middleware目录

  • 在目录中创建一个python文件

  • 在python文件中导入中间件的基类

from django.utils.deprecation import MiddlewareMixin
  • 在类中根据功能的需要,创建切入需求类,重写切入点方法
class AOP(MiddlewareMixin):

    def process_request(self, request):
        # 下面是实现10s内只能搜索1次的代码实现
        # 具体实现是通过redis缓存来实现,即缓存有效期为10s,如果来访者
        # IP在缓存中则此期间内无法进行种子搜索

        # 选择缓存
        cache = caches['redis_backend']

        # 如果是非第一次次访问就去缓存检查
        ip = request.META.get("REMOTE_ADDR")
        if cache.get(ip):
            return HttpResponse("<h1>您的搜索频率过高请稍后再试!</h1>")
        else:
            # 如果缓存中没有则可以进行访问,此时我们只做把来访者IP存入redis操作
            cache.set(ip, ip, timeout=10)
            pass
  • 启用中间件,在工程的setting.py中进行配置,在MIDDLEWARE中添加 middleware.文件名.类名

即在MIDDLEWARE列表中添加如下内容:

    'middleware.AOP.AOP',

然后重启服务器在浏览器中输入下面地址即可进行测试

http://127.0.0.1:8000/polls/bittorrent

第一次点击

10s内第二次,第三次… … 点击

1.2 频率控制实现

重写process_requests.py

class AOP(MiddlewareMixin):

    def process_request(self, request):
        ip = request.META.get("REMOTE_ADDR")

        cache = caches['redis_backend']

        results = cache.get(ip, [])

        # 当results非空并且当前时间和列表中最后一个时间戳的差值大于60s
        # 就将过期的数据弹出列表
        while results and time.time() - results[-1] > 60:
            results.pop()

        # 清空完过期的数据后如果列表中的记录数任大于 10;就拒绝服务
        if len(results) > 10:
            return HttpResponse("您的请求次数过多,请稍后再试!")

        # 如果是合法访问,就将内容插入列表,并将其写入缓存
        results.insert(0, time.time())
        cache.set(ip, results, timeout=60)

二.中间件小结

  • 调用顺序

    • 中间件注册的时候是一个列表

    • 如果我没有在切点处直接返回,中间件会依次执行

    • 如果我们直接进行返回,后续中间件就不再执行了

  • 切点

    • process_request

    • process_view

    • process_template_response

    • process_response

    • process_exception

本次测试仅测试了process_request这一个切点,对于其他切点可以以此类推。