本文目录导读:

在 PHP 中实现协程 HTTP 客户端,主要依赖于 Swoole 或 Workerman 等扩展。Swoole 是目前最主流的选择,因为它原生内置了协程 HTTP 客户端。
以下是关于 PHP 协程 HTTP 客户端的全面指南:
为什么使用协程 HTTP 客户端?
传统的 PHP HTTP 请求(如 curl)是同步阻塞的,无法并发,协程客户端可以:
- 并发执行:同时发送多个请求,总耗时取决于最慢的那个。
- 高吞吐量:在长连接场景下性能极高。
- 非阻塞:协程切换开销远小于进程/线程切换。
Swoole 协程 HTTP 客户端
基础用法(HTTP/1.1)
<?php
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;
run(function () {
$client = new Client('www.example.com', 80);
$client->set(['timeout' => 5]);
// 发起 GET 请求
$client->get('/');
echo "Status: " . $client->statusCode . PHP_EOL;
echo "Body: " . $client->body . PHP_EOL;
$client->close();
});
并发请求(核心优势)
这是协程的最大价值——并发请求:
<?php
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
run(function () {
$urls = [
'https://api.github.com',
'https://httpbin.org/get',
'https://example.com',
];
$start = microtime(true);
$results = [];
// 为每个 URL 创建一个协程
foreach ($urls as $index => $url) {
go(function () use ($url, &$results, $index) {
$client = new Client(parse_url($url, PHP_URL_HOST), 443, true); // true = SSL
$client->set(['timeout' => 10]);
$path = parse_url($url, PHP_URL_PATH) ?: '/';
$client->get($path);
if ($client->statusCode === 200) {
$results[$index] = $client->body;
} else {
$results[$index] = "Error: " . $client->statusCode;
}
$client->close();
});
}
// 等待所有协程完成(run 函数自动等待)
echo "Total time: " . (microtime(true) - $start) . " seconds\n";
print_r($results);
});
并发批量请求(使用 Channel 控制并发数)
为了避免产生过多协程,可以使用 Channel 作为并发限制:
<?php
use Swoole\Coroutine\Channel;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
run(function () {
$urls = [/* 100 个 URL */];
$concurrency = 10; // 同时最多 10 个请求
$channel = new Channel($concurrency);
$results = [];
// 生产者:填充任务
go(function () use ($channel, $urls) {
foreach ($urls as $url) {
$channel->push($url); // 会阻塞,直到有空间
}
$channel->close(); // 关闭通道,表示没有更多任务
});
// 消费者:N 个协程处理任务
for ($i = 0; $i < $concurrency; $i++) {
go(function () use ($channel, &$results) {
while (true) {
$url = $channel->pop();
if ($url === false) break; // 通道关闭,退出循环
$client = new Client(parse_url($url, PHP_URL_HOST), 443, true);
$client->get('/');
$results[$url] = $client->statusCode;
$client->close();
}
});
}
});
高级特性
HTTPS 与证书验证
$client = new Client('www.baidu.com', 443, true); // 启用 SSL
$client->set([
'ssl_host_name' => 'www.baidu.com', // SNI
'ssl_verify_peer' => false, // 开发环境可关闭证书验证
]);
连接复用(Keep-Alive)
协程客户端默认支持 keep-alive,在并发场景下自动复用连接,可以通过 set 方法配置:
$client->set([
'keep_alive' => true,
'keep_alive_idle_time' => 60, // 空闲 60 秒后关闭
]);
设置请求头与 Cookie
$client->setHeaders([
'User-Agent' => 'MyCoroutineClient/1.0',
'Accept' => 'application/json',
'Cookie' => 'session_id=abc123; user_id=42',
]);
上传文件
$client->addFile(__DIR__ . '/test.jpg', 'file_field', 'test.jpg', 'image/jpeg');
$client->post('/upload');
WebSocket 支持
Swoole 协程客户端同样支持 WebSocket:
$client = new Client('127.0.0.1', 9502);
$client->upgrade('/');
$client->push('Hello WebSocket');
$response = $client->recv();
与其他库的对比
| 特性 | Swoole 协程 | Guzzle (同步) | Guzzle (异步 promise) | cURL 多线程 |
|---|---|---|---|---|
| 并发能力 | ✅ 原生并发 | ❌ 串行 | ✅ 依赖事件循环 | ✅ 需手动管理 |
| 并发上限 | 极高(10万+) | 受内存限制 | 有限制 | |
| 代码可读性 | 极好(同步风格) | 好 | 回调地狱 | 复杂 |
| 性能 | 极快 | 一般 | 较好 | 中等 |
| 依赖 | Swoole 扩展 | Composer 包 | Composer 包 | PHP 内置 |
在 Laravel / Symfony 中使用
如果你在框架中使用 Swoole,通常配合 LaravelS 或 Swoft 等适配器。
// 在 Laravel 控制器中
public function fetchData()
{
$https = new HttpsClient();
$results = \Swoole\Coroutine\run(function () {
$c1 = new HttpsClient('https://api1.com');
$c2 = new HttpsClient('https://api2.com');
// 并发执行
return [$c1->get('/data1'), $c2->get('/data2')];
});
return response()->json($results);
}
常见问题与优化
超时处理
$client->set(['timeout' => 5]); // 秒
错误重试
for ($retry = 0; $retry < 3; $retry++) {
$client->get('/');
if ($client->statusCode === 200) break;
\Swoole\Coroutine\System::sleep(1); // 协程休眠,不阻塞其他协程
}
内存管理
高并发时建议:
- 使用
Co::set(['max_coroutine' => 100000])限制协程数 - 及时关闭连接:
$client->close() - 使用
channel控制并发上限,避免内存爆炸
不依赖 Swoole 的纯 PHP 协程
如果你无法安装 Swoole,可以使用 ReactPHP 或 AMPHP 的协程(基于 Promise + Generator),但性能远不及 Swoole。
- Swoole 协程 HTTP 客户端是 PHP 中实现高并发 HTTP 请求的最佳方案。
- 它写法简单(同步风格),性能极高(原生并发)。
- 核心功能:并发请求、连接复用、WebSocket、文件上传。
- 结合 Channel 可以实现优雅的并发控制。
如果你的项目长期运行且需要高并发,强烈推荐使用 Swoole;如果是 FPM 短生命周期场景,还是用 Guzzle 等同步库更合适。