PHP 协程HTTP客户端

wen PHP项目 4

本文目录导读:

PHP 协程HTTP客户端

  1. 为什么使用协程 HTTP 客户端?
  2. Swoole 协程 HTTP 客户端
  3. 高级特性
  4. 与其他库的对比
  5. 在 Laravel / Symfony 中使用
  6. 常见问题与优化
  7. 不依赖 Swoole 的纯 PHP 协程

在 PHP 中实现协程 HTTP 客户端,主要依赖于 SwooleWorkerman 等扩展。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,通常配合 LaravelSSwoft 等适配器。

// 在 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,可以使用 ReactPHPAMPHP 的协程(基于 Promise + Generator),但性能远不及 Swoole。


  • Swoole 协程 HTTP 客户端是 PHP 中实现高并发 HTTP 请求的最佳方案。
  • 它写法简单(同步风格),性能极高(原生并发)。
  • 核心功能:并发请求、连接复用、WebSocket、文件上传。
  • 结合 Channel 可以实现优雅的并发控制。

如果你的项目长期运行需要高并发,强烈推荐使用 Swoole;如果是 FPM 短生命周期场景,还是用 Guzzle 等同步库更合适。

抱歉,评论功能暂时关闭!