必须同时设置process-timeout和http-basic-timeout,因前者管控git clone、unzip等外部命令执行(默认300秒),后者管控单次HTTP请求全过程(DNS/TLS/首字节/body下载,默认60秒),二者作用阶段不同、互不替代,仅调其一无法解决Downloading卡顿或进程超时问题。

直接改 process-timeout 和 http-basic-timeout 两个值,缺一不可——只调一个,大概率还是卡在 Downloading https:// 或报 The process "" exceeded the timeout。
为什么必须同时设 process-timeout 和 http-basic-timeout
这两个超时控制完全不同的阶段,互不替代:
-
process-timeout管的是外部命令执行时间,比如git clone、unzip、运行post-install-cmd脚本。默认 300 秒,卡在这里会报[RuntimeException] The process "" exceeded the timeout -
http-basic-timeout(Composer 2.2+)管的是单次 HTTP 请求全过程:DNS 解析 + TLS 握手 + 首字节等待 + 整个 body 下载。默认仅 60 秒,卡在这里表现是反复retry或直接cURL error 28 - 即使
http-basic-timeout拉下了 ZIP,解压时仍可能被process-timeout杀掉;反过来,HTTP 请求早断了,process-timeout根本等不到解压那步
全局配置怎么写才真正生效
用 composer config -g 写入 ~/.composer/config.json,但有四个关键点容易踩坑:
- 必须两条命令都执行:
composer config -g process-timeout 1800和composer config -g http-basic-timeout 300(不支持合并在一条命令里) - 别漏掉
-g,否则只改当前项目,对composer global require无效 - 如果之前用
sudo composer config -g,配置可能写进了/root/.composer/config.json,而普通用户运行时读的是$HOME/.composer/config.json,实际没生效 - 改完立刻验证:
composer config -g --list | grep -E "(process-timeout|http-basic-timeout)",确保输出值是你刚设的
为什么换镜像比加 timeout 更重要
单纯拉长超时只是“等得更久”,不能解决连接抖动、首包延迟高、镜像不支持 Range 请求等根本问题。国内用户 80% 的“超时”其实是源不稳定导致的:
- 阿里云镜像地址必须完整且无尾部斜杠:
https://mirrors.aliyun.com/composer/(末尾/不能少,但也不能多写) - 设完必须清缓存:
composer clear-cache,否则旧的packages.json还在本地,根本不发请求 - 禁用 fallback 防止自动切回官方源拖慢流程:
composer config -g repo.packagist false - 验证是否真走镜像:
composer install -vvv 2>&1 | grep "Downloading.*packages.json",看到 URL 是mirrors.aliyun.com才算成功
PHP 底层 socket 超时会偷偷掐断连接
http-basic-timeout 设再大也没用,如果 PHP CLI 的 default_socket_timeout 更小——它会在底层直接中断连接:
- 查当前值:
php -i | grep default_socket_timeout,常见是 60 秒 - 若低于你设的
http-basic-timeout(比如设了 300),必须同步调高:php -d default_socket_timeout=300 -d max_execution_time=0 /usr/bin/composer install - 或者改
php.ini中的default_socket_timeout,但注意这是全局影响,CI 环境建议用-d参数临时覆盖
最常被忽略的是:设完配置后不验证、不清缓存、不看 -vvv 日志里的真实请求地址。超时问题表面是时间不够,本质是请求根本没发到正确的地方。











