ThinkPHP 6 的 throttle 中间件仅对显式绑定控制器方法的路由生效,闭包路由、资源路由未绑定或 Route::any+闭包均不触发;需确保使用 Redis 缓存驱动、正确配置反向代理 IP 头(如 X-Real-IP)、自定义中间件以支持接口级限流,并在异常处理器中手动添加 Retry-After 响应头。

ThinkPHP 6 的 throttle 中间件怎么配才生效
直接说结论:ThinkPHP 6 内置的 throttle 中间件默认只对「路由绑定控制器方法」生效,如果用的是闭包路由、资源路由未显式绑定、或接口走的是 Route::any + 闭包,它压根不触发。
常见错误现象是:加了 throttle:60,1 却完全没限流,Access-Control-Allow-Origin 头都出来了,但请求照发不误。
- 必须确保路由定义中明确绑定了控制器方法,例如
Route::get('api/user', 'Api/UserController@index'),而不是Route::get('api/user', function(){}) -
throttle默认使用cache驱动,确认config/cache.php中默认驱动不是file(并发下失效);推荐切到redis或memcached - IP 识别依赖
Request::ip(),如果你在 Nginx 后面且没配proxy_set_header X-Real-IP,它会把所有请求当成同一个 IP(通常是 127.0.0.1)来限流
自定义限流中间件时,$request->ip() 和 $request->header('X-Forwarded-For') 怎么选
别无脑用 X-Forwarded-For。它可被客户端伪造,直接拿来做限流会导致绕过或误杀。
正确做法是:只信任你反向代理(如 Nginx)添加的可信头,并在中间件里做白名单校验。
- 在 Nginx 配置中固定写死:
proxy_set_header X-Real-IP $remote_addr;,然后 PHP 里只取$request->header('X-Real-IP', $request->ip()) - 如果必须用
X-Forwarded-For,得配合trusted_proxies配置(在config/app.php中设置'trusted_proxies' => ['127.0.0.1', '10.0.0.0/8']),否则框架不会解析该头 - 测试时用
curl -H "X-Real-IP: 192.168.1.100" http://your.app/api/test比模拟真实链路更可控
Redis 存储 key 时,throttle 默认 key 是什么?能手动改吗
默认 key 是 throttle:ip:,不含路由名或用户 ID,意味着同一 IP 下所有接口共享计数——这在多数业务场景里不合理。123.123.123.123
想按接口维度限流?必须重写中间件逻辑,不能只靠配置。
- 复制
think\middleware\ThrottleRequests到本地中间件目录,修改getLimitedKey()方法,比如拼上$request->rule()或$request->url(true) - 注意:
$request->rule()在闭包路由下为空,此时建议 fallback 到$request->path() - key 长度别超 Redis 限制(512MB),避免用完整 URL;推荐哈希后截取,例如
substr(md5($key), 0, 16)
限流响应返回 429 但前端收不到 Retry-After 头
ThinkPHP 默认的 throttle 中间件根本没写这个头——它只抛异常,由全局异常处理兜底,而默认的 render() 方法压根不塞 Retry-After。
结果就是前端看到 429,但不知道等几秒再试,只能瞎重试或报错。
- 在自定义异常处理类(
app/exception/Handler.php)的render()方法里判断$e instanceof ThrottleRequestsException - 手动添加响应头:
$response->header('Retry-After', $e->getHeaders()['Retry-After'] ?? 1) - 注意:原异常里的
getHeaders()返回的是数组,其中Retry-After值来自availableIn秒数,单位是秒,不是毫秒
事情说清了就结束。真正麻烦的从来不是加一行中间件,而是弄明白你的流量路径里哪一层在伪造 IP、哪个缓存驱动在装睡、以及谁在默默吞掉关键响应头。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










