如何在Flask APIs中实现速率限制

1,229 阅读7分钟

在Flask APIs中实施速率限制

速率限制是一种在系统中限制网络流量的技术。它设定了一个限制,即用户在特定的时间范围内可以在系统中重复操作。

在这篇文章中,你将学习。

  • 什么是速率限制?
  • 限制网络请求率的好处。
  • 速率限制技术。
  • 如何在Flask APIs中实现速率限制技术。

前提条件

要遵循并完全理解本教程,你需要具备以下条件。

  • Python 3.6或更新版本。
  • 对Flask的基本了解。
  • 一个文本编辑器。

简介

速率限制控制一个操作的重复频率,并确保指导这个操作的设定约束不被超过(通常在特定的时间范围内)。

基本上,速率限制的过程包括以下程序。

  1. 系统为特定的操作定义了速率限制规则。
  2. 系统对启动用户的每个操作或请求进行统计。
  3. 请求的频率根据用户的需求而增加。
  4. 一旦频率达到系统的阈值(速率限制),进一步的请求就不会被处理,直到限制被取消(或修改)。

速率限制的好处

  • 通过缓解DDoS等网络攻击,提高安全效率。
  • 防止网络刮擦/机器人/垃圾邮件用户。
  • 防止服务器资源耗尽。
  • 管理内部/外部服务、政策和配额。
  • 控制系统进程和数据的流动。
  • 避免了高额的维护费用。

Flask网络框架

Flask是一个用Python编写的轻量级网络框架。它旨在使使用Python的网络开发变得快速和简单,并能建立复杂的应用程序。

速率限制技术

在一般情况下,速率是对系统中运行的操作次数的统计。有不同的技术来测量和限制速率。

它们包括。

  • 固定窗口:这种技术定义了在一个特定的时间内容纳的固定数量的请求。例如,设置每小时100个请求的窗口大小,意味着系统将只处理用户在该小时内提出的前100个请求,而每一个后续请求将被丢弃,直到下一个小时。
  • 滑动窗口:这种技术与固定窗口非常相似,即在一个特定的时间内允许有固定数量的请求。然而,它实现了一个滚动的时间窗口,以考虑到大量的请求高峰,这将降低固定窗口技术的效率。
  • Token Bucket:在这种技术中,系统不断计算用户在其内存(桶)中可以利用的代币数量,以提出请求。每当有请求提出时,就从桶中减少代币,直到代币用完为止。这种技术的一个优点是根据进程的操作能力,为不同的操作分配不同数量的代币。
  • 漏桶:这种技术与代币桶非常相似。然而,速率受限于从内存(桶)中泄漏出来的请求数量。这种技术首先确认系统有足够的处理能力来处理传入的请求,然后再进行处理,如果不能处理,就丢弃。

构建一个简单的Flask API

速率限制通常用于网络应用和API,以防止用户请求过度流入服务器。使用Python,让我们建立一个Flask API并在其中实现速率限制技术。

首先,你必须安装Flask网络框架,你将用它来构建API。

第1步

在终端中,输入。

pip install Flask

第2步

编写负责设置Flask API端点的代码。首先,创建一个名为app.py 的文件,并在其中保存以下代码。

from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
  return "Welcome to my Flask API"

if __name__ == "__main__":
  app.run()

在上面的代码中,你创建了一个简单的Flask应用程序,当索引路由被请求时渲染文本"Welcome to my Flask API" 。在运行Flask应用程序后,你应该得到一个类似于下图的响应。

Flask API response

在Flask中实现速率限制

在安装Flask框架并保存负责设置上述步骤中描述的端点的代码后,这里的下一步是安装Flask-Limiter库。

Flask-Limiter是一个Flask扩展,有助于在Flask应用程序中快速实现速率限制规则。

在终端,输入。

pip install Flask-Limiter

现在,你需要更新你的app.py 文件,并整合Flask-Limiter 库,为你的API中的特定端点定义速率限制规则。

导入Flask-Limiter库

from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

设置Flask-Limiter

limiter = Limiter(app, key_func=get_remote_address)

应用速率限制规则

@app.route("/")
@limiter.limit("10/minute") # maximum of 10 requests per minute
def index():
  return "Welcome to my Flask API"

在上面的代码中,你为端点定义了速率限制规则,将其设置为每60 秒接受每个API用户的请求10

如果超过了限制,用户就会收到响应--status code 429 (Too Many Requests) ,并出现如下图所示的错误页面。

Flask-Limiter limit exceeded error

Flask-Limiter在其[文档]中提供了一套用于定义速率限制规则的字符串符号,并给出了格式。

[count] [per|/] [n (optional)] [second|minute|hour|day|month|year]

你也可以通过用你选择的分隔符来组合多个速率限制。

例子包括。

  • 10/秒
  • 60/小时
  • 5/秒;60/分钟;2500/小时
  • 50/天,250/7天

探索Flask-Limiter的功能

我们将在本节中简要说明其中的一些功能。

设置默认费率限制规则

Flask-Limiter提供了设置默认速率限制规则的功能,Flask-Limiter将自动应用于你的Flask API中的每个端点。

要设置默认规则,请使用。

limiter = Limiter(
  app,
  key_func=get_remote_address,
  default_limits=["200/day", "50/hour"]
)

注意:如果一个端点在默认值已经存在的情况下定义其速率限制规则,新定义的规则将单独应用于路由,而默认值将被忽略。

要使一个路由使用默认规则并同时定义自己的规则,请在装饰器中使用override_defaults 参数,如图所示。

@app.route("/ping/")
@limiter.limit("1/second", override_defaults=False)
def ping():
  return "PONG"

某些端点也可以用@limiter.exempt 装饰器排除在应用默认速率限制规则之外,如图所示。

@app.route("/ping/")
@limiter.exempt
def ping():
  return "PONG"

使用自定义速率限制键

默认情况下,Flask-Limiter使用请求的remote address ,以识别与API互动的每个用户。Flask-Limiter提供了使用自定义用户标识符函数的功能,用于你需要用API密钥和用户名限制费率的事件。

你可以通过在初始化限制器时或在路由上应用@limiter.limit 装饰器时将自定义函数传递给key_func 参数来实现。

limiter = Limiter(app, key_func=custom_function_here)
@limiter.limit("10/minute", key_func=custom_function_here)

注意:自定义函数是从Flask请求上下文中调用的,必须返回一个字符串。

拥有多个速率限制规则

Flask-Limiter可以用来为一个特定的路由定义多个速率限制规则。

这可以通过代码来完成。

@app.route("....") # for a single decorator
@limiter.limit("100/day;10/hour;1/minute")
@app.route("....") # for multiple decorators
@limiter.limit("100/day")
@limiter.limit("10/hour")
@limiter.limit("1/minute")

生成自定义的超过限制的响应

默认情况下,Flask-Limiter在任何特定路线的费率限制被超过时,会触发abort(429) 。你可以通过为429 error code 注册一个错误处理程序来为用户定制这个响应,如下所示。

@app.errorhandler(429)
def ratelimit_handler(e):
  return "You have exceeded your rate-limit"

custom rate limit exceeded error

总结

在这篇文章中,我向你介绍了什么是速率限制,讨论了限制请求速率的重要性,包括减轻网络攻击,防止服务器资源耗尽,以及其他好处。还强调了一些标准的速率限制技术,并建立了一个Flask应用程序,在这个应用程序中,你可以通过不同的规则和自定义响应来实现速率限制技术。