乐趣区

关于flask:FlaskLimiter详细使用说明

本文首发于:行者 AI

速率限度通常作为服务的进攻措施予以施行。服务须要爱护本身免得适度应用(无论是无意还是无心),从而放弃服务可用性。在 Flask 我的项目开发过程中,遇到了须要对接口进行限度的需要,又不想去造轮子,这时候就须要用到 Flask-Limiter 这个三方库。本文将对 Flask-Limiter 的应用进行具体阐明。

1. 装置

装置依赖环境。

pip install Flask==1.1.1 Flask-Limiter==1.4

2. 疾速开始

有两种形式示意速率限度:

  • “100 per day”、”20 per hour”、”5 per minute”、”1 per second”
  • “100/day”、”20/hour”、”5/minute”、”1/second”

速率限度能够设置全局配置,针对所有接口进行限度;也能够通过装璜器进行部分限度;对于不想限度的接口,能够通过装璜器 @limiter.exempt 进行解除限制。示例代码如下所示:

app = Flask(__name__)

# 该配置为全局配置、实用于所有接口
limiter = Limiter(app, key_func=get_remote_address, default_limits=["100 per day", "10/hour"])

# @limiter.limit: 将笼罩全局 limiter 配置
@app.route("/slow")
@limiter.limit("1 per day")
def slow():
    return ":("

# override_defaults: 示意该 limiter 是否笼罩全局 limiter 限度,默认为 True
@app.route("/medium")
@limiter.limit("1/second", override_defaults=False)
def medium():
    return ":|"

# 残缺继承全局 limiter 配置
@app.route("/fast")
def fast():
    return ":)"

# @limiter.exempt: 被装璜的视图不受全局速率限度
@app.route("/ping")
@limiter.exempt
def ping():
    return "PONG"

3. 装璜器

依据集体爱好和应用场景,有以下几种形式:
繁多润饰:限度字符串能够是单个限度,也能够是定界符分隔的字符串。

@app.route("....")
@limiter.limit("100/day;10/hour;1/minute")
def my_route()
  ...

多个装璜器:限度字符串能够是单个限度,也能够是定界符分隔的字符串,也能够是两者的组合。

@app.route("....")
@limiter.limit("100/day")
@limiter.limit("10/hour")
@limiter.limit("1/minute")
def my_route():
  ...

自定义性能:默认状况下,依据 Limiter 实例初始化时所应用的要害性能来利用速率限度。开发者能够实现本人的性能。

def my_key_func():
  ...

@app.route("...")
@limiter.limit("100/day", my_key_func)
def my_route():
  ...

动静加载限度的字符串:在某些状况下,须要从代码内部的源(数据库,近程 api 等)中检索速率限度。这能够通过向装璜器提供可调用对象来实现。

留神:所装璜的路由上每个申请都会调用提供的可调用对象,对于低廉的检索,请思考缓存响应。

def rate_limit_from_config():
    return current_app.config.get("CUSTOM_LIMIT", "10/s")

@app.route("...")
@limiter.limit(rate_limit_from_config)
def my_route():
    ...

4. 限度域

指依据什么进行限度,对应的参数为 key_funcflask_limiter.util 提供了两种形式:

  • flask_limiter.util.get_ipaddr():应用 X-Forwarded-For 标头中的最初一个 IP 地址,否则回退到申请的remote_address
  • flask_limiter.util.get_remote_address():应用申请的remote_address

留神:在实在开发中,大部分我的项目都配置了 Nginx,如果间接应用 get_remote_address,获取到的是 Nginx 服务器的地址,相当于来自该 Nginx 服务器的所有申请会被当做同一个 IP 拜访,所以我的项目中个别都是自定义 key_func!

def limit_key_func():
    return str(flask_request.headers.get("X-Forwarded-For", '127.0.0.1'))

获取 IP 的根据是依据 Nginx 的配置决定的:

X-Forwarded-For # 个别是每一个非通明代理转发申请时会将上游服务器的 ip 地址追加到 X -Forwarded-For 的前面,应用英文逗号宰割;X-Real-IP # 个别是最初一级代理将上游 ip 地址增加到该头中;X-Forwarded-For # 是多个 ip 地址,而 X -Real-IP 是一个;# 如果只有一层代理,这两个头的值就是一样的。

5. 共享限度

实用于速率限度由多条路由共享的状况。

命名共享限度:通过雷同的 shared_limit 对象进行装璜。

mysql_limit = limiter.shared_limit("100/hour", scope="mysql")

@app.route("..")
@mysql_limit
def r1():
   ...

@app.route("..")
@mysql_limit
def r2():
   ...

动静共享限度:将可调用对象作为范畴传递,该函数的返回值将用作范畴。留神,callable 具备一个参数:示意申请端点的字符串。

def host_scope(endpoint_name):
    return request.host
host_limit = limiter.shared_limit("100/hour", scope=host_scope)

@app.route("..")
@host_limit
def r1():
   ...

@app.route("..")
@host_limit
def r2():
   ...

6. 贮存后端

记录 IP 拜访次数,用于判断该 IP 拜访次数是否达到限度。Limiter 默认应用内存作为贮存后端,然而在理论开发中,可能会波及到多过程资源不共享、服务器内存耗费等问题,个别是应用 redis 作为贮存后端。

  • 须要 redis 服务器的地位,以及可选的数据库号。redis://localhost:6379redis://localhost:6379/n(对于数据库 n)。
  • 如果 redis 服务器正在通过 unix 域套接字监听,则能够应用redis+unix:///path/to/sockredis+unix:///path/to/socket?db=n(对于数据库 n)。
  • 如果数据库受密码保护,则能够在 URL 中提供明码,例如,redis://:foobared@localhost:6379或者redis+unix//:foobered/path/to/socket
# LIMITS_REDIS_STORAGE 就是上文提到的 redis 的 URI
limiter = Limiter(default_limits=["100 per day"], key_func=limit_key_func, storage_uri=LIMITS_REDIS_STORAGE)

7. 总结

通过对 API 申请的限度和配额,在肯定水平上能防止零碎收到超出其解决能力的数据,确保零碎的资源能失去正当的应用。以上就是本文的全部内容,心愿能给大家学习带来帮忙。

退出移动版