缓存前缀必须按域名区分,否则多域名共用同一ThinkPHP应用时会发生缓存键冲突、页面错乱和数据污染;需在config/cache.php中用闭包动态生成前缀,并为CLI等场景提供域名fallback机制。

缓存前缀为什么必须按域名区分
多个域名共用同一套 ThinkPHP 应用时,如果缓存前缀(cache.prefix)没做隔离,index.html 页面在 site-a.com 写入的缓存可能被 site-b.com 读取或覆盖——尤其当两个域名共享 Redis 或文件缓存目录时,缓存键冲突直接导致页面错乱、数据污染。
ThinkPHP 本身不自动识别域名并切换前缀,必须手动干预缓存驱动初始化时机。
在 config/cache.php 中动态生成前缀
最稳妥的做法是在缓存配置中用闭包或函数动态返回前缀值,确保每次请求都基于当前域名计算:
'prefix' => function () {
$host = $_SERVER['HTTP_HOST'] ?? 'default';
// 去掉端口,兼容 localhost:8080 等场景
$host = preg_replace('/:\d+$/', '', $host);
return strtolower(str_replace(['.', '_'], '-', $host)) . '_';
},
- 这个闭包会在每次创建缓存实例时执行,天然适配多域名
- 注意:仅对使用
Cache::store()或自动注入的缓存实例生效;若手动 newRedisCache等驱动类,前缀不会自动应用 - 避免用
$_SERVER['SERVER_NAME'],它可能被伪造或未设置,HTTP_HOST更可靠
Redis 场景下额外注意数据库编号与命名空间
即使前缀已按域名区分,若多个域名共用同一个 Redis db(如都用 db=0),仍存在 key 扫描、清空缓存时误删的风险:
立即学习“PHP免费学习笔记(深入)”;
- 推荐为每个域名分配独立
db,在config/cache.php的redis配置里动态指定:'database' => (int)array_search($_SERVER['HTTP_HOST'] ?? 'default', ['site-a.com' => 0, 'site-b.com' => 1]) - 更稳妥的是用前缀 +
SCAN隔离,但 Redis 6+ 才支持 ACL 级别隔离,老版本只能靠前缀硬约束 - 测试时用
redis-cli -n 0 keys "site-a-com_*"验证 key 是否真的隔离
命令行任务(如定时器)如何处理域名前缀
Artisan 命令或 php think xxx 运行时没有 HTTP_HOST,$_SERVER['HTTP_HOST'] 为空,会导致前缀变成 default_ 或报错:
- 在闭包中 fallback 到配置项:
$host = $_SERVER['HTTP_HOST'] ?? config('app.default_domain', 'cli'); - 启动命令时显式传入域名:
php think cache:clear --domain=site-a.com,并在命令逻辑中写入$_SERVER['HTTP_HOST'] = $input->getOption('domain'); - 关键点:所有 CLI 场景必须明确“归属哪个域名”,否则缓存清理、预热会出错
多域名缓存真正难的不是写法,而是确认所有入口(Web、CLI、Worker、API Gateway 转发)都走同一套域名提取逻辑,漏掉一个就可能让缓存前缀失效。



















