在 Laravel 5.6 中,还引入了频率限制功能。所谓频率限制,指的是在指定时间单个用户对某个路由的访问次数限制,该功能有两个使用场景,一个是在某些需要验证/认证的页面限制用户失败尝试次数,提高系统的安全性,另一个是避免非正常用户(比如爬虫)对路由的过度频繁访问,从而提高系统的可用性,此外,在流量高峰期还可以借助此功能进行有效的限流。
在 Laravel 中该功能通过内置的 throttle
中间件来实现,该中间件接收两个参数,第一个是次数上限,第二个是指定时间段(单位:分钟):
Route::middleware('throttle:60,1')->group(function () {
Route::get('/user', function () {
//
});
});
以上路由的含义是一分钟能只能访问路由分组的内路由(如 /user
)60 次,超过此限制会返回 429 状态码并提示请求过于频繁。
如果你觉得这种静态设置频率的方式不够灵活,还可以通过模型属性来动态设置频率,例如,我们可以为上述通过 throttle
中间件进行分组的路由涉及到的模型类定义一个 rate_limit
属性,然后这样来动态定义这个路由:
Route::middleware('throttle:rate_limit,1')->group(function () {
Route::get('/user', function () {
// 在 User 模型中设置自定义的 rate_limit 属性值
});
Route::get('/post', function () {
// 在 Post 模型中设置自定义的 rate_limit 属性值
});
});
这样,我们就可以通过为不同的模型类设置不同的 rate_limit
属性值来达到动态设置频率限制的效果了。
Lumen 使用 throttle 限制接口访问频率:
开始
首先我们要在app\Http\Middleware
中新建ThrottleRequests.php
文件。
并且把以下链接中的代码拷贝到这个文件中:
https://github.com/illuminate/routing/blob/master/Middleware/ThrottleRequests.php
接着修改文件中的命名空间:
namespace App\Http\Middleware;
标记同一用户端请求
因为Lumen
框架缺失部分功能,我们需要修改ThrottleRequests.php
中的resolveRequestSignature
方法:
protected function resolveRequestSignature($request){
return sha1(
$request->method() .
'|' . $request->server('SERVER_NAME') .
'|' . $request->path() .
'|' . $request->ip()
);
}
抛出响应
throttle
超过限制时抛出的是Illuminate\Http\Exceptions\ThrottleRequestsException
,同样Lumen
框架缺少这个文件,需要自己定义一下,在app/Exceptions
中新建ThrottleException.php
,写入以下代码:
<?php
namespace App\Exceptions;
use Exception;
class ThrottleException extends Exception{
protected $isReport = false;
public function isReport(){
return $this->isReport;
}
}
在app/Exceptions/Handler.php
捕获该抛出异常,在render
方法增加以下判断:
if ($exception instanceof ThrottleException) {
return response([
'code' => $exception->getCode(),
'msg' => $exception->getMessage()
], 429);
}
修改ThrottleRequests.php
文件中的buildException
方法:
protected function buildException($key, $maxAttempts){
$retryAfter = $this->getTimeUntilNextRetry($key);
$headers = $this->getHeaders(
$maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
$retryAfter
);
// 修改了这一行
return new ThrottleException('Too Many Attempts.', 429);
}
需在文件头部中添加这一行:
use App\Exceptions\ThrottleException;
注册中间件
在bootstrap/app.php
中注册:
$app->routeMiddleware([
'throttle' => App\Http\Middleware\ThrottleRequests::class,
]);
到这里我们就加入成功了,接着在路由中添加中间件即可:
$router->group(['middleware' => ['throttle:10,2']],function() use ($router){
$router->post('feedback','UserController@addFeedback');
});
其中throttle:10,2
表示的是2分钟内访问10次。