企业级场景下真正能稳定落地的不是私有镜像,而是satis生成的静态仓库;直接配置repo.packagist仅接管元数据请求,zip包仍从原始dist.url下载,不受控制且易因权限、限流或cdn导致失败。

composer 搭建“私有镜像”这个说法本身容易误导——**企业级场景下,真正能稳定落地的不是镜像,而是 Satis 生成的静态仓库**。硬要镜像 packagist.org 官方源,不配反向代理 + OAuth token 透传 + 缓存穿透防护,composer install 必然随机失败。
为什么直接改 repo.packagist 不等于“有了私有镜像”
执行 composer config -g repo.packagist composer https://my-mirror.com/ 只接管元数据(packages.json、provider-*.json)请求,但 ZIP 包仍从原始 dist.url 下载(比如 GitHub Releases)。而这些地址:
• 不受你控制
• 需要 X-OAuth-Scopes 头才能访问(否则 403)
• 被 CDN 或 rate limit 拦截后无 fallback
• 国内公开镜像(阿里云、USTC)根本不托管 ZIP,只做元数据 redirect
验证方式:composer show vendor/package --verbose,看输出里 dist.url 字段是不是还在指向 GitHub/GitLab。
satis.json 配置里三个必填字段漏一就失效
Satis 不是服务,是构建工具;它不校验配置语法,但缺关键字段会导致 packages.json 为空或客户端拒绝加载。
-
"name"和"homepage"必须同时存在,且homepage是完整 HTTPS URL,末尾带/(如"https://pkgs.internal/") -
"archive"块必须显式声明:{"directory": "dist", "format": "zip", "skip-dev": true};否则 CI 构建时拉不到 ZIP 包 -
"repositories"数组里每个项必须是"type": "vcs"(Git 地址),不能写成"type": "package"或混在require里
常见错误:satis build 成功但 packages.json 里没包——大概率是某个 Git 仓库没打语义化 tag(v1.0.0),或 composer.json 里缺 dist 字段。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
Nginx 托管 packages.json 的三个硬性响应要求
Satis 输出的 public/ 目录扔到 Nginx 就完事?错。Composer 对 HTTP 响应极其挑剔:
- URL 必须以
/结尾(https://pkgs.internal/),否则拼出https://pkgs.internalpackages.json→ 404 -
packages.json响应头必须含Content-Type: application/json;Nginx 需显式配置:types { application/json json; },不能依赖自动推断 -
dist/下的 ZIP 文件必须可直连 GET(如https://pkgs.internal/dist/vendor/pkg/abc123.zip),SELinux 或文件权限常锁死该路径
调试命令:curl -I https://pkgs.internal/packages.json,确认状态码 200 + Content-Type 正确 + Content-Length 非零。
客户端 composer.json 启用私有源的三要素
只往 repositories 里加一条 URL,composer install 依然 fallback 到公网——因为 Composer 默认把 packagist.org 当权威源。
- 私有源必须放在
repositories数组首位,且"type": "composer"(不是package或vcs) -
url值末尾必须带/(如"https://pkgs.internal/") -
"packagist.org": false必须与repositories同级,不能嵌套在任意源对象内部
错误示范:"repositories": [{"type":"composer","url":"https://pkgs.internal"}], "packagist.org": {"allow":false} —— 这个 allow 写法完全无效。
php bin/satis build 是唯一触发点,CI 里跑它比什么都重要。










