You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10:ThrottleRequest结合缓存实现限流异常排查

API限流计数未重置问题修复

你要实现的是:正式环境60分钟内允许100次请求,测试环境5秒内10次,超时后计数重置为0,但现有代码在5秒后仍限制请求,核心问题出在计数存储和逻辑流程上,具体问题及修复方案如下:

现有代码的问题

  • 计数存储错误:把请求次数存在数据库的ignore_limits字段里,这是持久化存储,不会自动重置。即使缓存超时后把变量$requests设为0,后续又会从数据库读取旧值覆盖,导致重置无效。
  • 逻辑顺序混乱:超时分支重置$requests后,else分支又将其赋值为数据库的ignore_limits值,等于白重置了。
  • 调试语句阻断执行:dd(Cache::has($key));会直接中断代码,后续的缓存更新、数据库保存都不会执行。

修复后的代码

$key = $request->apikey;
$apiKey = ApiKey::where('key', $key)->first();
if (!$apiKey) {
    return response()->json(['message' => '无效的API密钥'], 401);
}

// 根据环境自动切换限流规则
if (app()->environment('production')) {
    $rateLimit = 100;
    $timer = 3600; // 60分钟=3600秒
} else {
    $rateLimit = 10;
    $timer = 5; // 测试环境5秒
}

// 定义规范的缓存键名
$countCacheKey = "api_rate:{$key}";
$timerCacheKey = "api_rate_timer:{$key}";

// 从缓存获取当前计数和上次请求时间,默认0
$requests = Cache::get($countCacheKey, 0);
$lastRequestTime = Cache::get($timerCacheKey, 0);

// 超时则重置计数
if (time() - $lastRequestTime > $timer) {
    $requests = 0;
}

// 检查是否超限流
if ($requests >= $rateLimit) {
    return response()->json(['message' => '请求次数超过限制'], 429);
}

// 更新缓存:计数+1,同时设置过期时间
Cache::put($countCacheKey, $requests + 1, now()->addSeconds($timer));
Cache::put($timerCacheKey, time(), now()->addSeconds($timer));

return $next($request);

修复说明

  1. 改用缓存存储计数:缓存是临时存储,既可以自动过期,也能在超时后主动重置,完全符合限流的临时计数需求,不需要再操作数据库的ignore_limits字段(如果这个字段没用可以直接删掉)。
  2. 调整逻辑顺序:先判断超时重置计数,再检查是否超限流,流程更清晰。
  3. 移除调试语句:确保代码能完整执行。
  4. 环境自动适配:根据应用环境自动切换正式/测试的限流参数,不用手动修改。

内容的提问来源于stack exchange,提问作者Kyuzzero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:05:28