codecamp

速率限制(Rate Limiting)

速率限制

为防止滥用,你应该考虑对您的 API 限流。 例如,您可以限制每个用户 10 分钟内最多调用 API 100 次。 如果在规定的时间内接收了一个用户大量的请求,将返回响应状态代码 429 (这意味着过多的请求)。

要启用限流, ​user identity class​ 应该实现 ​yii\filters\RateLimitInterface​。 这个接口需要实现以下三个方法:

  • getRateLimit()​:返回允许的请求的最大数目及时间,例如,​[100, 600]​ 表示在 600 秒内最多 100 次的 API 调用。
  • loadAllowance()​:返回剩余的允许的请求和最后一次速率限制检查时 相应的 UNIX 时间戳数。
  • saveAllowance()​:保存剩余的允许请求数和当前的 UNIX 时间戳。

你可以在 user 表中使用两列来记录容差和时间戳信息。 loadAllowance() 和 saveAllowance() 可以通过实现对符合当前身份验证的用户的这两列值的读和保存。 为了提高性能,你也可以考虑使用缓存或 NoSQL 存储这些信息。

用户模型中的实现如下所示:

public function getRateLimit($request, $action)
{
    return [$this->rateLimit, 1]; // $rateLimit requests per second
}
public function loadAllowance($request, $action)
{
    return [$this->allowance, $this->allowance_updated_at];
}
public function saveAllowance($request, $action, $allowance, $timestamp)
{
    $this->allowance = $allowance;
    $this->allowance_updated_at = $timestamp;
    $this->save();
}

一旦 identity 实现所需的接口,Yii 会自动使用 ​yii\filters\RateLimiter ​为 ​yii\rest\Controller ​配置一个行为过滤器来执行速率限制检查。如果速度超出限制, 该速率限制器将抛出一个 ​yii\web\TooManyRequestsHttpException​。

你可以参考以下代码 在你的 REST 控制器类里配置速率限制:

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['rateLimiter']['enableRateLimitHeaders'] = false;
    return $behaviors;
}

当速率限制被激活,默认情况下每个响应将包含以下 HTTP 头发送目前的速率限制信息:

  • X-Rate-Limit-Limit​:同一个时间段所允许的请求的最大数目;
  • X-Rate-Limit-Remaining​:在当前时间段内剩余的请求的数量;
  • X-Rate-Limit-Reset​:为了得到最大请求数所等待的秒数。

你可以禁用这些头信息通过配置 ​yii\filters\RateLimiter::$enableRateLimitHeaders​ 为 false, 就像在上面的代码示例所示。


授权验证(Authentication)
版本化(Versioning)
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }