/**
* 检测用户访问页面频率
* 如果5秒内访问超过15次,将返回429状态页面
*/
$identity = generateIdentityCode();
$counts = Cache::tag('VisitEnvironment')->remember($identity, 1, 5);
//5秒内访问超过15次
if ($counts > 15) {
return response(View::fetch(app()->getRootPath() . 'view/429.html'), 429);
} else {
Cache::inc($identity);
}
这是我以前写的一个控制访问频率的中间件,最近研究发现了问题,如果打开页面,控制在5秒内打开新网页链接或刷新页面,$counts的值必然达到15次。
主要是Cache::inc之后会增加缓存的存在时间,只要控制在5秒内,这个缓存就一直存在,当达到15次之后就必然跳到429页面,恶心的是,因为缓存不过期$counts会一直增加,页面就一直显示429页面。
发现问题就解决问题:
$key = self::KEY_PREFIX . generateIdentityCode();
$now = microtime(true);
$list = Cache::get($key, []);
$list = array_values(array_filter($list, fn($t) => ($now - $t) < self::WINDOW_SECONDS));
if (count($list) >= self::MAX_REQUESTS) {
return response(View::fetch(app()->getRootPath() . 'view/429.html'), 429);
}
$list[] = $now;
Cache::set($key, $list, 3600);
通过AI的帮助,建议将file缓存找成redis缓存,redis缓存的功能更好,但是出于经济问题是,还是继续使用file缓存,将代码更新了。
将一些数据设置成了常量,核心改为:每次访问会增加本次时间戳的记录,读取数据时,会过滤掉与上次访问时间之间的间隔超过设定时间的时间戳。然后统计数据量,如果超过了设定值就会跳转到429页面。