4

Laraval Rate Limit

 2 years ago
source link: http://froyot.github.io/2019/08/01/laraval-rate-limit.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Laraval Rate Limit

01 Aug 2019 Category:

layout: post title: Dingo Api 的限流在Laravel的限流基础上做了哪些修改? category: php comments: true description: Dingo Api 的限流在Laravel的限流基础上做了哪些修改 keywords: Dingo,Laravel,api限流 —

今天看文档的时候看到 Laravel的 节流限速 (throttling) 。网络上搜索,又看到了Dingo 的节流限速的文档。因此查看Laravel 与Dingo的源码,对比两者之间的相同点与不同点。

  • 两者都是通过中间件处理请求限流

  • 处理方式都是记录缓存key,设置过期时间,在没过期的时候自增,直到超出限制,或key过期

Laravel 限流中间件 Illuminate\Routing\Middleware\ThrottleRequests


public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
{
  $key = $this->resolveRequestSignature($request);

  $maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);

  if ($this->limiter->tooManyAttempts($key, $maxAttempts, $decayMinutes)) {
    throw $this->buildException($key, $maxAttempts);
  }

  $this->limiter->hit($key, $decayMinutes);

  $response = $next($request);

  return $this->addHeaders(
    $response, $maxAttempts,
    $this->calculateRemainingAttempts($key, $maxAttempts)
  );
}

Dingo 限流中间件Dingo\Api\Http\Middleware\RateLimit

public function handle($request, Closure $next)
{
  if ($request instanceof InternalRequest) {
    return $next($request);
  }

  $route = $this->router->getCurrentRoute();

  if ($route->hasThrottle()) {
    $this->handler->setThrottle($route->getThrottle());
  }

  $this->handler->rateLimitRequest($request, $route->getRateLimit(), $route->getRateLimitExpiration());

  if ($this->handler->exceededRateLimit()) {
    throw new RateLimitExceededException('You have exceeded your rate limit.', null, $this->getHeaders());
  }

  $response = $next($request);

  if ($this->handler->requestWasRateLimited()) {
    return $this->responseWithHeaders($response);
  }

  return $response;
}

  • 从上面两个中间件的代码可以看出,Laravel只有再没有超过限制的情况下才会对缓存进行+1操作,而Dingo是先操作再进行判断

  • Dingo 限制key以请求路径hash为前缀,默认以用户ip作为key。因此可以实现对用户每个url的限制,限制粒度更细

Dingo\Api\Http\RateLimit\Handler代码如下:

$this->keyPrefix = sha1($request->path());
...
public function getRateLimiter()
{
  return call_user_func($this->limiter ?: function ($container, $request) {
    return $request->getClientIp();
  }, $this->container, $this->request);
}

  • Laravel 中使用用户信息或域名+ip作为限制key,限制粒度只在用户级别

Illuminate\Routing\Middleware\ThrottleRequests代码如下:

  protected function resolveRequestSignature($request)
  {
    if ($user = $request->user()) {
      return sha1($user->getAuthIdentifier());
    }
    if ($route = $request->route()) {
      return sha1($route->getDomain().'|'.$request->ip());
    }
  }
  • Dingo支持修改限制key,Laravel默认没有支持修改方法

  • Dingo支持添加多个限制规则,逻辑上使用限制数最小的进行判断。因此假设有两个限制器,且都符合限制条件。一个限制1分钟10次,另一个限制2分钟15次,会使用1分钟1次的进行限制判断。

  • Dingo 返回了过期限制到期时间,Laravel默认不返回限制到期时间

Dingo\Api\Http\RateLimit\Handler获取限制最少的限制器代码如下:

public function rateLimitRequest(Request $request, $limit = 0, $expires = 0)
{
  ...
  $this->throttle = $this->getMatchingThrottles()->sort(function ($a, $b) {
        return $a->getLimit() < $b->getLimit();
      })->first();
  ...
}

Dingo\Api\Http\RateLimit\Handler获取设置的返回头信息代码如下:

protected function getHeaders()
{
  return [
    'X-RateLimit-Limit' => $this->handler->getThrottleLimit(),
    'X-RateLimit-Remaining' => $this->handler->getRemainingLimit(),
    'X-RateLimit-Reset' => $this->handler->getRateLimitReset(),
  ];
}

Illuminate\Routing\Middleware\ThrottleRequests获取设置的返回头信息代码如下:


protected function getHeaders($maxAttempts, $remainingAttempts, $retryAfter = null)
{
  $headers = [
    'X-RateLimit-Limit' => $maxAttempts,
    'X-RateLimit-Remaining' => $remainingAttempts,
  ];

  if (! is_null($retryAfter)) {
    $headers['Retry-After'] = $retryAfter;
    $headers['X-RateLimit-Reset'] = $this->availableAt($retryAfter);
  }

  return $headers;
}

两者实现原理相同,只是在细节上Dingo的功能更加强大。Dingo 限制粒度系,限制规则上,可扩展性,灵活性都比Laravel强。

来发评论吧~
Powered By Valine
v1.4.18

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK