Composer配代理必须同时设http-proxy和https-proxy,只配前者会导致HTTPS请求静默直连而卡在“Loading composer repositories”;https-proxy值必须以http://开头,即使代理监听TLS端口,且需URL编码特殊字符,加-g全局配置并验证两字段均存在。

Composer配代理必须同时设 http-proxy 和 https-proxy
只配 http-proxy 会导致所有 HTTPS 请求(包括访问 Packagist、GitHub)静默 fallback 到直连,最终卡在 Loading composer repositories 且无明确报错。因为 Composer 对协议路由是硬分离的:http-proxy 仅用于 HTTP 请求,https-proxy 才用于建立 CONNECT 隧道——哪怕你的代理监听的是 TLS 端口,它的值也必须是 http:// 开头。
常见错误写法包括:https://127.0.0.1:8080、127.0.0.1:8080、漏掉认证信息中的 URL 编码(如密码含 @ 或 / 未转义)。正确示例:http://user:pa%40ss%2Fword@127.0.0.1:8080。
- 务必加
-g(即--global),否则只写入当前项目composer.json,换目录就失效 - 验证是否生效:运行
composer config -g --list | grep -E "(http|https)-proxy",确认两行都存在且格式合法 - Windows 下若报
Could not write to file,检查%APPDATA%\Composer\config.json是否存在且可写
Composer异步任务队列依赖状态管理
Composer 2.0+ 内置了基于状态机的任务队列机制,不是靠外部消息队列实现的。每个 HTTP 下载任务都有明确生命周期:STATUS_QUEUED → STATUS_STARTED → STATUS_COMPLETED / STATUS_FAILED / STATUS_ABORTED。这种设计让并发控制和失败恢复更可控,比如 HttpDownloader 类中 $maxJobs=12 和 $runningJobs 就是直接参与调度的核心字段。
你无法手动干预这个队列,但可以影响其行为:
- 通过
process-timeout控制单个任务最大执行时间(默认 300 秒),设为0表示禁用超时 - 网络不稳定时,Composer 会自动重试最多 3 次,但不会跨状态重试(比如
STATUS_FAILED不会自动变回STATUS_QUEUED) - 任务失败后,错误由
EventDispatcher统一捕获,日志里看到的Script [...] terminated with an exception就是这一层抛出的
NTLM 代理环境下必须引入中转代理
Composer 原生不支持 NTLM 认证。即使你填了 http-proxy 和 https-proxy,只要代理返回 407 Proxy Authentication Required,Composer 就会直接失败,没有任何降级或提示逻辑。
唯一可行方案是本地起一个支持 NTLM 的中转代理(如 cntlm 或 px),让它监听 127.0.0.1:3128 并处理域认证,再让 Composer 连这个地址。临时验证方法:curl -x http://127.0.0.1:3128 -I https://packagist.org/packages.json —— 如果 curl 也报 407,说明中转层没配通。
别指望 HTTP_PROXY 环境变量能绕过:Composer 明确忽略它,只认自己的配置项。
生产部署时队列行为与本地开发本质不同
composer install 在生产环境不是“启动一个队列”,而是严格按 composer.lock 顺序串行安装——它跳过了依赖解析阶段,也不启用并发下载。真正用到异步队列逻辑的是 composer update 或首次 install 且无 lock 文件时。
这意味着:
- 线上部署应始终用
composer install --no-dev --no-interaction --optimize-autoloader --no-progress,这些参数不改变队列逻辑,但避免交互、进度条、dev 包等干扰 -
--optimize-autoloader生成静态映射,和队列无关,但它让后续 PHP 请求更快,间接降低因 autoload 延迟引发的超时风险 - 如果部署卡住,优先检查是否误用了
composer update(尤其在 CI 中没锁住版本),而不是怀疑队列并发数
最易被忽略的一点:Composer 的“队列”是内存内短生命周期结构,不持久化、不跨进程、不支持断点续传。一旦中断,就得重来——它不是 Enqueue 或 Laravel Horizon 那类作业队列。


















