// application/middleware/CheckRequest.php
namespace app\middleware;
use think\facade\Redis;
class CheckRequest
{
public function handle($request, \Closure $next)
{
$ip = $request->ip(); // 获取用户IP地址
$key = 'req_limit:' . $ip;
$maxRequests = 5; // 时间窗口内的最大请求数
$windowSize = 300; // 时间窗口大小,单位为秒(例如,5分钟)
$current = time(); // 当前时间戳
// 获取当前IP的请求记录(时间戳数组)
$timestamps = Redis::lrange($key, 0, -1);
// 过滤掉时间窗口之外的请求时间戳
$timestamps = array_filter($timestamps, function ($timestamp) use ($current, $windowSize) {
return $current - $timestamp < $windowSize;
});
if (count($timestamps) >= $maxRequests) {
// 超过请求限制
return json(['error' => '请求过于频繁,请稍后再试。'], 429);
} else {
// 将当前请求时间戳添加到记录中
Redis::rpush($key, $current);
// 设置过期时间,以清除旧的请求记录
Redis::expire($key, $windowSize);
}
return $next($request);
}
}
在这个例子中,我们维护了一个时间戳的列表,其中每个时间戳代表一次请求。当新请求到达时,我们移除所有超出时间窗口的时间戳,只保留窗口内的时间戳。这样,如果用户在第一分钟做了四次请求,在第二分钟做了一次请求,到了第六分钟时,第一分钟的请求已经不在窗口内了,因此用户可以再次进行请求。
发表评论 取消回复