PHP的cURL本身是同步阻塞的,无法原生异步;真正异步需借助多进程、Swoole协程、ReactPHP等外部模型,或采用后台任务+回调的伪异步方案。

PHP 用 cURL 异步获取远程文件不成立
PHP 的 cURL 扩展本身是同步阻塞的,没有原生异步机制。所谓“cURL 异步”,实际是靠多进程、多线程、协程或事件循环模拟出来的,并非 cURL 自身能力。直接写 curl_exec() 就是同步下载,哪怕加了 CURLOPT_TIMEOUT_MS 或 CURLOPT_NOSIGNAL,也不能让单次请求变“异步”。
想真正异步,得换底层模型
PHP 原生不支持 I/O 异步,必须借助外部模型实现并发请求。常见可行路径有:
-
多进程:用
pcntl_fork()启多个子进程,各自调curl_exec();适合 CLI 场景,Web 环境(如 Apache/FPM)下不稳定,容易失控 -
Swoole 协程:启用
Swoole\Coroutine\Http\Client,支持真正的并发 HTTP 请求,代码简洁且性能高;需安装 Swoole 扩展(>= v4.8),运行在swoole_http_server或coroutine环境中 -
ReactPHP / Amp:基于事件循环的异步框架,用
React\HttpClient或Amp\Http\Client发起非阻塞请求;依赖 Composer 包,学习成本略高,但纯 PHP 实现、无需扩展
最实用的伪异步方案:后台任务 + 回调
多数 Web 场景不需要实时返回文件内容,而是“发起后不管,结果存库/发消息”。这时更稳的做法是:
- 用户请求触发一个后台任务(如写入 Redis 队列、调用
shell_exec("nohup php fetch.php &")) - 后台脚本用普通
cURL同步下载,完成后写入本地文件或数据库字段 -
前端轮询
/api/status?id=xxx查状态,或用 WebSocket 推送完成事件
这样既避开 PHP 同步瓶颈,又不强依赖扩展或新框架,兼容所有环境。
立即学习“PHP免费学习笔记(深入)”;
// 示例:后台下载脚本 fetch.php(CLI 模式)
$remoteUrl = $argv[1] ?? 'https://example.com/file.zip';
$localPath = '/tmp/' . basename(parse_url($remoteUrl, PHP_URL_PATH));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remoteUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FILE, fopen($localPath, 'w'));
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200 && file_exists($localPath)) {
echo "Download OK: $localPath\n";
} else {
echo "Download failed: $httpCode\n";
}
别踩这些坑
很多人误以为加个 CURLOPT_TIMEOUT_MS 或开 curl_multi 就算异步,其实不是:
-
curl_multi是并发(concurrent),不是异步(asynchronous);它仍需你主动调curl_multi_exec()轮询,期间 PHP 线程仍被占用 -
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false)不等于“不等响应”,只是不把 body 返回给变量,依然会阻塞到传输结束 - FPM 下用
ignore_user_abort(true)+fastcgi_finish_request()只能提前断开连接,背后请求仍是同步执行,超时或错误照样卡住 worker
真要异步,就得接受模型切换——要么进协程世界(Swoole),要么进队列系统(Redis + Worker),或者交出去(用 Node.js / Python FastAPI 做代理)。PHP 的 cURL 就是个老实干活的搬运工,别指望它自己跑起来。











