// 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);
    }
}
在这个例子中,我们维护了一个时间戳的列表,其中每个时间戳代表一次请求。当新请求到达时,我们移除所有超出时间窗口的时间戳,只保留窗口内的时间戳。这样,如果用户在第一分钟做了四次请求,在第二分钟做了一次请求,到了第六分钟时,第一分钟的请求已经不在窗口内了,因此用户可以再次进行请求。