答案是Composer本地复用15分钟内未过期的packages.json缓存,导致依赖解析基于旧元数据;需用composer update --refresh(≥2.5)强制刷新元数据,或手动删除对应repo缓存目录,并逐层校验镜像p2接口一致性。

Composer 镜像源的数据不一致,不是“镜像坏了”,而是你本地拿到的元数据和镜像站当前实际同步状态之间存在三重错位:缓存时效、分片异步、CDN 节点偏差。
为什么 composer update 找不到新发布的包
根本原因不是镜像没同步,而是 Composer 默认复用本地 packages.json 缓存(15 分钟内不过期),哪怕镜像站已更新,你本地仍按旧索引解析依赖。典型现象:
- 官网
packagist.org/packages/monolog/monolog已显示 v3.0.0,但composer show monolog/monolog只列到 v2.9.1 -
composer update --dry-run输出含Resolving dependencies,说明它根本没读composer.lock,而是重新查元数据 —— 且查的是过期缓存 -
curl -I https://mirrors.aliyun.com/composer/packages.json返回HTTP/2 200,但响应头Age: 1800表示 CDN 缓存了 30 分钟前的数据
验证镜像元数据是否真正一致的三个硬指标
不能只看 packages.json 的 lastModified,必须逐层校验目标包对应的具体 provider 文件。一致性需同时满足:
-
curl -I https://mirrors.aliyun.com/composer/p2/monolog/monolog.json返回状态码为200(不是404或304) - 响应头
Last-Modified与官方源相差 ≤ 180 秒(curl -I https://packagist.org/p2/monolog/monolog.json对比) - JSON 中
.packages."monolog/monolog"的版本键集合完全一致:curl -s URL | jq -r '.packages."monolog/monolog" | keys[]' | sort两站输出逐行比对
项目级 repositories 配置会彻底屏蔽全局镜像
只要 composer.json 里有 "repositories" 字段,Composer 就无视 composer config --global repo.packagist 的所有设置。常见陷阱:
- 配置写成
"repos.packagist"(多一个s)——静默失败,无提示 - 镜像 URL 少了末尾
/,如"https://mirrors.aliyun.com/composer"→ 拼出的请求路径变成/composer/packages.json,404 后自动 fallback 到官方源 - 未在
repositories数组首位声明{"packagist.org": false},导致 Composer 2.2+ 仍会回退查询官方源,造成元数据混杂
composer update --refresh 是最轻量精准的刷新方式
该命令专为解决元数据滞后设计,仅丢弃 packages.json 和所有 provider-*.json 缓存,不重下 ZIP 包。但前提是:
- Composer 版本 ≥ 2.5(老版本不支持,只能手动删缓存目录)
- 先确认生效镜像:
composer config repo.packagist(不带-g,项目级优先)输出是你配的地址 - 执行前确保
composer.lock未被意外修改,否则--refresh仍可能因 lock 锁定旧 dist URL 而失效
真正容易被忽略的是:即使镜像站页面显示“最后同步时间:2 分钟前”,你本地命中的 CDN 节点可能缓存着半小时前的数据;而 composer clear-cache 根本不碰这些元数据文件,清了也白清。











