冒烟测试必须直接检测真实元数据端点如 /packagist.org/packages.json,响应码需为200且无重定向,配合--max-time 5、flock防并发、编码与gzip健壮处理,并行检测多镜像,优先项目级配置并验证实际请求域名。

curl -I 测 packages.json 是唯一轻量可靠的冒烟入口
只测 https://mirrors.aliyun.com/composer/ 首页 HTTP 状态码是无效的——Composer 实际请求的是 /packagist.org/packages.json 或 /p2/ 接口,首页 200 不代表元数据服务可用。很多脚本因此误判“镜像正常”,结果 composer install 卡在 “Loading composer repositories”。
- 必须用
curl -I或curl -s -o /dev/null -w "%{http_code}"直接访问真实元数据端点,例如:https://mirrors.aliyun.com/composer/packagist.org/packages.json - 响应状态码必须为
200,且不能是301/302重定向(重定向会绕过镜像站,直连 packagist.org) - 加
--max-time 5防止慢响应拖垮定时任务;不加-L,避免隐藏重定向行为 - 别信
composer diagnose:它只检查本地配置语法,不发起真实网络请求,完全无法反映镜像连通性
PHP 脚本里解析 packages.json 必须处理编码、gzip 和 JSON 错误
直接 json_decode(file_get_contents($url)) 在生产环境大概率静默失败——镜像源返回的 packages.json 可能带 BOM、用 GBK 编码、或启用 gzip 压缩,而 Composer 自身解压逻辑不会暴露给脚本。
- 用
stream_context_create()显式禁用压缩:'http' => ['header' => 'Accept-Encoding: identity'] - 读取后先调
mb_detect_encoding($content, ['UTF-8', 'GBK'], true)判定真实编码,再mb_convert_encoding($content, 'UTF-8', $detected) -
json_decode()必须加JSON_THROW_ON_ERROR标志,否则返回null且无提示,后续逻辑全崩 - 别依赖
json_last_error_msg():它不保留上下文,出错时你不知道是哪个 URL、哪个字段导致的
Linux 定时任务中防止并发检测触发风控封禁
Cron 默认不保证单实例,若某次检测因 DNS 解析慢或镜像站响应卡顿耗时超长,下次触发时旧进程仍在运行,就会并发请求同一镜像源——高频探测极易被识别为扫描行为,触发限流甚至 IP 封禁。
- 用
flock -n /tmp/composer-health-check.lock包裹整个脚本,确保同一时间只跑一个实例 - 在脚本开头加
trap 'rm -f /tmp/composer-health-check.lock' EXIT,避免异常退出后锁残留 - 检测超时阈值设为
--max-time 5,但 Cron 的*/5 * * * *间隔不能低于 60 秒——给足缓冲,避免连续探测 - 别把多个镜像源塞进同一个
curl命令串行测:一个慢就拖垮全部;应并行启动独立子进程,各自带flock和超时
项目级配置比全局配置更可控,但容易被覆盖
composer config -g repo.packagist 看着方便,但在 CI/CD、Docker 构建、宝塔后台等多用户场景下基本失效——不同用户有各自的 COMPOSER_HOME,全局配置根本读不到。
- 优先用项目级配置:
composer config repo.packagist composer https://mirrors.aliyun.com/composer/(注意末尾斜杠,缺了就拼成/composerpackages.json导致 404) - 该命令写入
composer.json的repositories.packagist字段,可提交 Git,团队行为一致 - 如果项目
composer.json中repositories是数组([]),命令会失败;需先手动改为对象({})再执行 - 检查是否生效:运行
composer show -p,看实际请求域名是不是你配的镜像地址——这才是唯一可信依据,composer config -g repo.packagist显示为空也不影响
真正的健康检查不是“测得快”,而是“测得准、跑得稳、不扰民”。每个环节都得考虑镜像站的真实行为(比如同步延迟、CDN漂移)、Composer 的实际请求路径、以及自动化脚本在复杂环境下的鲁棒性。漏掉任意一环,冒烟测试就变成“烟雾弹”。











