如何限制我网站的 API 用户?
- 2024-10-29 08:35:00
- admin 原创
- 91
问题描述:
我网站的合法用户偶尔会向服务器发送 API 请求,导致不良结果。我想设置一个限制,即每 5 秒最多调用一次 API 或每分钟最多调用 n 次(尚未确定确切的限制)。我显然可以在数据库中记录每个 API 调用,并对每个请求进行计算,以查看它们是否超出限制,但每个请求的所有这些额外开销都会违背目的。我可以使用哪些其他资源密集程度较低的方法来设置限制?我使用的是 PHP/Apache/Linux,仅供参考。
解决方案 1:
好吧,没有办法在不对服务器进行任何$last_api_request
写入的情况下完成我所要求的操作,但我至少可以消除记录每个请求的麻烦。一种方法是使用“漏桶”节流方法,该方法仅跟踪最后一个请求( )和时间范围内请求数/限制的比率($minute_throttle
)。漏桶永远不会重置其计数器(与每小时重置一次的 Twitter API 节流不同),但如果桶已满(用户已达到限制),他们必须等待n
几秒钟让桶变空一点,然后才能发出另一个请求。换句话说,它就像一个滚动限制:如果在时间范围内有先前的请求,它们会慢慢从桶中漏出;只有当您填满桶时,它才会限制您。
此代码片段将$minute_throttle
针对每个请求计算一个新值。我指定分钟是$minute_throttle
因为您可以为任何时间段添加节流阀,例如每小时、每天等……尽管添加多个节流阀很快就会让用户感到困惑。
$minute = 60;
$minute_limit = 100; # users are limited to 100 requests/minute
$last_api_request = $this->get_last_api_request(); # get from the DB; in epoch seconds
$last_api_diff = time() - $last_api_request; # in seconds
$minute_throttle = $this->get_throttle_minute(); # get from the DB
if ( is_null( $minute_limit ) ) {
$new_minute_throttle = 0;
} else {
$new_minute_throttle = $minute_throttle - $last_api_diff;
$new_minute_throttle = $new_minute_throttle < 0 ? 0 : $new_minute_throttle;
$new_minute_throttle += $minute / $minute_limit;
$minute_hits_remaining = floor( ( $minute - $new_minute_throttle ) * $minute_limit / $minute );
# can output this value with the request if desired:
$minute_hits_remaining = $minute_hits_remaining >= 0 ? $minute_hits_remaining : 0;
}
if ( $new_minute_throttle > $minute ) {
$wait = ceil( $new_minute_throttle - $minute );
usleep( 250000 );
throw new My_Exception ( 'The one-minute API limit of ' . $minute_limit
. ' requests has been exceeded. Please wait ' . $wait . ' seconds before attempting again.' );
}
# Save the values back to the database.
$this->save_last_api_request( time() );
$this->save_throttle_minute( $new_minute_throttle );
解决方案 2:
您可以使用令牌桶算法来控制速率,该算法与漏桶算法类似。请注意,您必须在进程之间(或您想要控制的任何范围)共享桶的状态(即令牌数量)。因此,您可能需要考虑锁定以避免竞争条件。
好消息:我为你做了所有这些:带宽限制/令牌桶
use bandwidthThrottle okenBucketRate;
use bandwidthThrottle okenBucketTokenBucket;
use bandwidthThrottle okenBucketstorageFileStorage;
$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate = new Rate(10, Rate::SECOND);
$bucket = new TokenBucket(10, $rate, $storage);
$bucket->bootstrap(10);
if (!$bucket->consume(1, $seconds)) {
http_response_code(429);
header(sprintf("Retry-After: %d", floor($seconds)));
exit();
}
解决方案 3:
最简单的解决方案就是每 24 小时为每个 API 密钥提供有限数量的请求,并在某个已知的固定时间重置它们。
如果他们的 API 请求用尽了(即计数器达到零或限制,取决于您计数的方向),则停止向他们提供数据,直到您重置计数器为止。
这样,他们就不会向你提出太多要求,这对他们最有利。
解决方案 4:
我不知道这个线程是否还活着,但我建议将这些统计数据保存在 memcached 等内存缓存中。这将减少将请求记录到数据库的开销,但仍能达到目的。
解决方案 5:
您说“每个请求的所有这些额外开销都会违背目的”,但我不确定这是否正确。目的不就是防止服务器受到攻击吗?这可能是我实现它的方式,因为它实际上只需要快速读取/写入。如果您担心性能,您甚至可以将 API 服务器检查外包给不同的数据库/磁盘。
但是,如果您想要其他选择,您应该查看mod_cband,这是一个旨在帮助带宽限制的第三方 Apache 模块。尽管它主要用于限制带宽,但它也可以根据每秒请求数进行限制。我从未使用过它,所以不确定您会得到什么样的结果。还有另一个名为 mod-throttle 的模块,但该项目似乎现已关闭,并且从未为 Apache 1.3 系列以上的任何版本发布过。
解决方案 6:
除了从头开始实施之外,您还可以查看 API 基础设施,例如 3scale ( http://www.3scale.net ),它可以进行速率限制以及许多其他功能(分析等)。它有一个 PHP 插件: https: //github.com/3scale/3scale_ws_api_for_php。
您还可以在 API 前面粘贴类似 Varnish 的东西,然后像那样进行 API 速率限制。
解决方案 7:
难道这不是通过会话就能简单完成的吗?
microtime()
與比較$_SESSION['last_access_microtime']
。
解决方案 8:
在 node js 中,有一个名为expess-rate-limiter的包,它正好可以完成您想要完成的任务。
它限制了一段时间内的请求数量。我不知道 PHP 中是否有同样的东西。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件