ThinkPHP接口限流失败的核心原因是路由绑定、IP识别、缓存驱动三者未对齐:仅显式绑定控制器的路由触发throttle;Nginx未透传X-Real-IP导致IP全为127.0.0.1;file缓存驱动使Cache::inc()恒返回false,限流逻辑静默失效。

ThinkPHP部署后接口限流失败,核心问题往往不在代码逻辑本身,而在于生产环境三处关键配置未对齐:路由绑定方式、IP识别链路、缓存驱动类型。默认配置在本地开发能跑通,一上Nginx+Redis就静默失效——不是没触发,是根本没进限流逻辑。
路由没绑定控制器,中间件压根不执行
throttle中间件只对显式绑定控制器方法的路由生效。以下写法完全绕过限流:
-
Route::get('api/user', function() { ... });(闭包路由) -
Route::resource('posts', 'PostController');(未显式指定@index等方法) -
Route::any('api/data', [...]);(泛匹配)
必须改用明确绑定:
Route::get('api/user', 'Api/UserController@index');- 资源路由加约束:
Route::resource('posts', 'PostController')->only(['index', 'show']);
IP全变成127.0.0.1,所有用户共享一个计数器
Nginx反代后,$request->ip()默认返回代理地址。没配透传头,限流就变成“全站共用1个额度”。
立即学习“PHP免费学习笔记(深入)”;
- Nginx配置必须加:
proxy_set_header X-Real-IP $remote_addr; - PHP中取IP不能只写
$request->ip(),要fallback:$request->header('X-Real-IP', $request->ip()) - 若用
X-Forwarded-For,需在config/app.php中配置可信代理:'trusted_proxies' => ['127.0.0.1']
缓存驱动还是file,计数恒为0
file驱动下Cache::inc()永远返回false,导致限流逻辑误判为“首次访问”,实际不限制。
- 检查
config/cache.php:'default' => 'redis'(不能是file) - 确认
config/redis.php中连接参数正确,且Redis服务可达 - 临时验证:在控制器里写
dump(Cache::inc('test_key'));,返回数字才正常
Key设计不合理,不同接口互相污染
默认throttle的key只含IP,api/user和api/order共用一个计数器。攻击者刷一个接口就能拖垮整个API。
- 自定义中间件时,key应拼接路径:
'rate_limit:' . $request->ip() . ':' . md5($request->path()) . ':' . date('Y-m-d H:i') - 时间窗口必须用
date('Y-m-d H:i'),不用time(),避免并发跨秒导致计数翻倍 - 闭包路由下
$request->rule()为空,要fallback到$request->path()



















