thinkphp 实现不同二级域名短信验证码独立限频,关键是将子域名作为缓存键前缀嵌入发送逻辑:通过解析 host 获取子域名,构造如“{$subdomain}:{$mobile}”的带域名片键,并结合分钟/小时双维度计数限流,配合中间件前置校验确保执行时机。

ThinkPHP 实现不同二级域名下的短信验证码独立限频,关键不在“绑定域名”本身,而是把子域名作为限流维度嵌入到发送逻辑中。不是靠配置文件自动区分,而是主动提取 Host 信息,构造带域名标识的缓存键,并统一走同一套防刷规则。
一、先确保二级域名能被正确识别
无论 TP5.1 还是 TP6,都要让框架或代码能拿到真实访问的子域名:
- TP6 多应用模式下,确认已开启 'url_domain_deploy' => true(不是 APP_SUB_DOMAIN_DEPLOY,那是旧版)
- TP5.1 若未开启子域名部署,可直接用 $request->host() 或 $_SERVER['HTTP_HOST'] 手动解析,例如:
$host = $_SERVER['HTTP_HOST']; $subDomain = strtok($host, '.'); - Nginx/Apache 必须透传 Host 头,不能在反向代理时覆盖或丢弃
二、短信发送类中加入域名维度缓存键
发送前校验频率时,不能只用手机号做 key,必须拼上子域名,才能实现“admin.example.com 和 api.example.com 各自独立计数”:
- 推荐写法:Cache::tag('sms')->set("{$subDomain}:{$mobile}", $code, 300)(5分钟有效期)
- 避免裸键如
"sms:{$mobile}",否则所有域名共享同一缓存,起不到隔离作用 - 若用 Redis 驱动,tag 能保证批量清理可控;若用 File 驱动,多机部署会失效,生产环境务必切 Redis
三、设计分层限频策略(按域名+手机号双控)
一个手机号在不同子域名下可各自触发限制,但也要防单个域名内高频刷:
- 每分钟最多发送 1 次:Cache::get("send_limit:{$subDomain}:{$mobile}:minute"),命中则拒绝
- 每小时最多 5 次:Cache::inc("send_limit:{$subDomain}:{$mobile}:hour", 1),首次设 TTL=3600
- 全局兜底:同一子域名下,任意手机号 1 小时内累计超 100 次请求,临时封该域名入口(可选)
四、路由与中间件配合保障执行时机
限频逻辑必须在控制器调用前完成,尤其要避开路由匹配之后才执行:
- TP6:把校验逻辑写成中间件,注册在 app/middleware.php 全局队列最前面
- TP5.1:建议在 app/common/behavior/CheckSmsLimit.php 中实现,并在 tags.php 中挂载到
action_begin - 不要在控制器里先生成验证码再校验——容易绕过,也增加无效开销
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











