Composer 与 Packagist 安装依赖失败:curl error 28 超时、GitHub 限流、镜像切换与内存不足全解
写 PHP 项目绕不开 Composer:新建 Laravel 项目要执行 composer create-project,接手老项目第一件事是 composer install。可在国内执行时,终端常常卡在「Loading composer repositories with package information」很久不动,接着报「curl error 28 while downloading https://repo.packagist.org/p2/...: Operation timed out」;或者元数据下载完了,开始安装时一行行刷出「Failed to download xxx from dist」,然后「Now trying to download from source」,开始用 git 克隆,慢得令人绝望;还有人看到「GitHub API limit exhausted」,被要求创建一个令牌。
这些报错对应的是不同阶段。Composer 先从 repo.packagist.org 下载包的元数据,解析出要装哪些版本;然后按 composer.lock 或解析结果下载每个包的压缩包,压缩包大多托管在 GitHub 的代码下载服务上;压缩包下载失败时,它会退回到用 git 克隆源码。所以元数据超时要处理 Packagist 的连接,压缩包失败要处理 GitHub 的连接与限流,两段分开处理效率最高。另有一类报错与网络无关,例如依赖冲突与内存不足,也会在下文单独列出。
Composer 两段下载分别走哪里
看报错时先找地址:出现 packagist 就是元数据阶段,出现 github 或 codeload 就是压缩包阶段,出现 could not be resolved 就是版本冲突。国内镜像能同时缓存元数据与压缩包,但不覆盖私有包,也可能比官方晚几分钟到几小时。
| 阶段 | 默认地址 | 典型报错 | 处理方向 |
|---|---|---|---|
| 包元数据 | repo.packagist.org | curl error 28 或 packages.json 无法下载 | 线路或镜像 |
| 代码压缩包 | GitHub 代码下载服务 | Failed to download from dist | 线路与 GitHub 令牌 |
| 回退源码克隆 | github.com 的 git 仓库 | git clone 超时或很慢 | 安装 zip 扩展避免回退 |
| GitHub 接口 | api.github.com | API limit exhausted | 配置 GitHub 令牌 |
| 私有包 | 私有仓库或 Satis | 401 或 403 | auth.json 凭据 |
| 依赖解析 | 本地计算 | could not be resolved to an installable set | 改版本约束,与网络无关 |
从卡住到装好依赖:分步操作
- 第一步:先把网络线路准备好。安装刺猬VPN,自定义用户名和密码注册,不需要邮箱和手机号,连上后先用浏览器打开 repo.packagist.org/packages.json 与 github.com,两个都能打开再回到终端。免费节点永久免费、不限流量、不限速,适合先判断是不是网络问题;
- 第二步:让终端用上线路。Composer 读取 HTTP_PROXY、HTTPS_PROXY 与 NO_PROXY 环境变量,Windows PowerShell 用 $env:HTTPS_PROXY 设置,macOS 与 Linux 写进 shell 配置文件;执行 composer diagnose,看「Checking https connectivity to packagist」一项是否为 OK;
- 第三步:确认没有残留的镜像配置。执行 composer config -g repos.packagist 查看全局仓库设置,如果指向一个已经停止服务的镜像,用 composer config -g --unset repos.packagist 删掉,恢复官方源;
- 第四步:配置 GitHub 令牌。在 GitHub 的「Settings」「Developer settings」「Personal access tokens」里生成一个只读令牌,执行 composer config -g github-oauth.github.com 你的令牌,从此 GitHub 接口限额会大幅提高;
- 第五步:检查 PHP 扩展。执行 php -m 看是否有 zip 与 openssl,缺少 zip 扩展又没有 unzip 命令时,Composer 会提示「The zip extension and unzip/7z commands are both missing」并回退到 git 克隆,安装扩展后速度会快很多;
- 第六步:清缓存后重试。执行 composer clear-cache,再执行 composer install -vvv,详细输出会显示每个请求的地址与耗时,卡在哪里一目了然;
- 第七步:大型项目内存不足时,报「Allowed memory size of ... bytes exhausted」,临时设置环境变量 COMPOSER_MEMORY_LIMIT=-1 再执行,或者升级到 Composer 2,它的内存占用小得多;
- 第八步:安装完成后,把 composer.lock 提交进仓库,团队其他成员与部署环境执行 composer install 时会按锁文件下载同一组版本,不必重新解析。
按报错的那一行排查
- curl error 28 Operation timed out:到 Packagist 的连接超时,确认代理变量在当前终端生效,或临时切换镜像;
- packages.json file could not be downloaded:元数据入口打不开,用浏览器访问同一地址对比,浏览器能开就是终端代理没生效;
- Failed to download from dist 后转为 source:压缩包下载失败,检查到 GitHub 的连接与 zip 扩展;
- GitHub API limit exhausted:未登录的接口限额用完,配置 GitHub 令牌;
- SSL certificate problem: unable to get local issuer certificate:PHP 找不到根证书,在 php.ini 里设置 openssl.cafile 指向有效的证书包,或关闭杀毒软件的 HTTPS 扫描;
- Your requirements could not be resolved to an installable set of packages:版本冲突,阅读报错里的依赖链,调整 composer.json 的版本约束或 PHP 版本;
- The process exceeded the timeout of 300 seconds:某个进程执行太久,设置 COMPOSER_PROCESS_TIMEOUT 为更大的值。
官方源、国内镜像与线路怎么选
镜像的优势是不需要代理,缺点是可能滞后、偶尔停服,而且你刚发布的新版本要等镜像同步才能装。团队里有人维护自己的开源包,或者依赖刚发布的修复版本,直连官方更省心。刺猬VPN支持按域名的智能分流,可以只让 packagist.org 与 github.com 相关域名走线路,国内服务照常直连。实际可用性取决于当前网络环境。
| 对比项 | 会员节点直连官方 | 国内镜像 | 免费节点 |
|---|---|---|---|
| 包的新鲜度 | 与 Packagist 实时一致 | 可能延迟几分钟到几小时 | 与官方一致 |
| 压缩包下载 | 直接从 GitHub 下载 | 镜像缓存,速度较快 | 直接从 GitHub 下载 |
| 私有包 | 支持 | 不覆盖 | 支持 |
| 配置成本 | 设一次代理变量 | 一条 composer config 命令 | 同左 |
| 流量 | 时长套餐有效期内不限流量、不限速 | 由镜像决定 | 永久免费、不限流量、不限速 |
| 适合场景 | 日常开发与发布新版本 | 只装常用包且能接受延迟 | 先判断是不是网络问题 |
Windows、macOS 与 Docker 环境的差异
Windows 上最常见的问题是 PHP 的 openssl 与 curl 扩展没启用,或者 php.ini 有多份,命令行用的不是你改过的那份。执行 php --ini 看命令行实际加载的配置文件路径,在那份文件里启用扩展。环境变量设在 PowerShell 窗口里只对当前窗口有效,长期使用要在系统的环境变量设置里添加。
macOS 用 Homebrew 安装的 PHP 与系统自带的 PHP 可能同时存在,执行 which php 确认用的是哪一个。Docker 容器里执行 composer install 时,容器默认不继承宿主机的代理设置,要在 docker run 时用 -e 传入代理变量,或者在 Dockerfile 里用构建参数传入,构建完成后别把代理写死进镜像。持续集成里缓存 Composer 的缓存目录,可以避免每次构建都重新下载。
锁文件、团队协作与部署
composer.lock 记录了每个依赖的确切版本与下载地址,应用项目应当提交它。团队成员执行 composer install 时按锁文件下载,结果完全一致;只有在需要升级依赖时才执行 composer update,并把更新后的锁文件提交。如果有人在镜像环境下执行了 update,锁文件里的下载地址可能变成镜像地址,其他人直连官方时仍然能用,因为 Composer 会按仓库设置重新定位,但最好在团队里统一一种来源,避免混乱。
部署到生产服务器时,执行 composer install --no-dev --optimize-autoloader,只装生产依赖并优化自动加载。服务器在境外时一般不存在网络问题;服务器在国内时,要么配置镜像,要么在构建机上装好依赖再连同 vendor 目录一起部署,不要让生产服务器在发布时临时去拉依赖。
Composer 1 与 Composer 2 的差别
还在用 Composer 1 的老项目,网络问题会被放大很多。Composer 1 的元数据格式要一次下载大量文件,单线程逐个下载压缩包,内存占用也高;Composer 2 改用了更精简的元数据格式,并行下载压缩包,速度与稳定性都明显更好。执行 composer --version 确认版本,如果还是 1.x,执行 composer self-update --2 升级。
升级前确认项目里的插件兼容 Composer 2,少数老插件只支持 1.x,升级后会报插件 API 版本不匹配。遇到这种情况先升级插件本身;实在不能升级,可以用 composer self-update --1 临时退回。官方对 Composer 1 的元数据支持已经大幅缩减,长期来看迟早要迁移。
新建项目时的特殊情况
执行 composer create-project 新建 Laravel、Symfony 等框架项目时,Composer 先下载框架骨架,再安装骨架里声明的全部依赖,一次要下载上百个包,是最容易超时的场景。如果中途失败,生成的目录里只有一半文件,不要在这个半成品上继续执行 install,直接删掉整个目录重新创建,否则锁文件与 vendor 目录可能对不上。
很多框架安装器本质上也是调用 Composer,例如 Laravel 的安装器,它同样读取 Composer 的代理与镜像设置。创建项目后框架往往还会自动执行一些脚本,例如生成密钥、发布配置,这些脚本失败时报的是 PHP 错误而不是下载错误,要按报错信息单独处理。
私有包与凭据配置
公司内部的私有包通常放在私有 Git 仓库、Satis 或 Private Packagist 上,需要在 composer.json 的 repositories 里声明地址,并提供凭据。凭据不要写进 composer.json,而是写进项目根目录或用户目录下的 auth.json,并把项目里的 auth.json 加入 .gitignore,避免令牌被提交进仓库。
私有仓库报 401 或 403 时,先确认令牌没有过期、权限包含读取该仓库;报超时时,先确认私有仓库本身的地址能访问。私有包的地址不在国内镜像的覆盖范围内,切换镜像对它没有任何作用,这一点常被忽略。如果私有仓库在公司内网,记得把它的域名写进 NO_PROXY,否则请求会被送到外部线路上,反而连不上。
迁移到新电脑时的顺序
- 先安装 PHP 并启用 openssl、curl、zip、mbstring 等常用扩展,执行 php -m 确认;
- 安装 Composer 2,执行 composer --version 看到版本号再继续;
- 设置代理变量或镜像,执行 composer diagnose,所有检查项为 OK;
- 配置 GitHub 令牌与私有仓库的 auth.json;
- 最后进入项目执行 composer install,不要把旧电脑的 vendor 目录直接拷过来,PHP 版本不同时扩展编译结果可能不兼容。
和其他开发下载工具的分工
PHP 项目的前端部分往往还要用 npm,有时还要拉 Docker 镜像,这些工具各有自己的镜像与代理配置,不要用 Composer 的设置去修它们,统一的排查思路见 npm、pip、Docker 拉取失败排查。
Composer 的压缩包与源码克隆都依赖 GitHub,克隆慢、下载慢、Git 推送超时的处理方法见 GitHub 访问与下载加速。先让 GitHub 稳定可用,Composer 的大部分问题就随之消失。
常见报错速查表
| 现象 | 原因 | 解决办法 |
|---|---|---|
| curl error 28 | 到 Packagist 超时 | 确认代理变量生效或切换镜像 |
| Failed to download from dist | GitHub 压缩包下载失败 | 检查 GitHub 连接与 zip 扩展 |
| API limit exhausted | GitHub 接口限额用完 | 配置 GitHub 令牌 |
| SSL certificate problem | PHP 找不到根证书 | 设置 openssl.cafile |
| could not be resolved | 版本约束冲突 | 调整 composer.json |
| Allowed memory size exhausted | 内存不足 | COMPOSER_MEMORY_LIMIT=-1 |
| exceeded the timeout | 进程超时 | 加大 COMPOSER_PROCESS_TIMEOUT |
高频问答
- 问:设置了系统代理为什么 Composer 还是超时?答:Composer 读的是 HTTPS_PROXY 等环境变量,在终端里显式设置一次;
- 问:镜像和官方源能混用吗?答:可以,但同一项目最好统一,避免锁文件里的地址混乱;
- 问:GitHub 令牌需要什么权限?答:只读公共仓库即可,不要给多余的写权限;
- 问:composer update 和 install 有什么区别?答:install 按锁文件安装,update 会重新解析并改写锁文件;
- 问:为什么装得特别慢?答:多半是缺少 zip 扩展导致回退到 git 克隆,或者 GitHub 连接不稳;
- 问:免费节点够用吗?答:够判断网络问题,首次安装大型项目建议用时长套餐,有效期内不限流量、不限速。
把 Composer 环境一次配稳
Composer 与 Packagist 安装失败,拆开看是元数据、压缩包、GitHub 接口三段各自的问题,外加与网络无关的版本冲突和内存不足。先让浏览器能打开对应地址,再让终端代理生效、配好 GitHub 令牌、装上 zip 扩展,用 composer diagnose 与 -vvv 输出逐段验证,问题就能快速定位。
刺猬VPN采用 HTTPS+AES 加密传输,自定义用户名和密码即可匿名注册,不需要邮箱和手机号;免费节点永久免费、不限流量、不限速;时长套餐有效期内不限流量、不限速,客户端支持按域名与 IP 的智能分流和断线保护,一个账号可在多台开发机上使用。依赖能否顺利下载取决于当前网络环境。
开发者的稳定通道:用刺猬VPN流畅访问 GitHub 与全球开发资源
刺猬VPN提供永久免费节点,不限流量;无需邮箱,自定义用户名即可匿名注册。一个账号支持多设备同时在线,实际可用性取决于当前网络环境。