swlib/saber · 上手攻略

  • 仓库:swlib/saber
  • 链接:https://github.com/swlib/saber
  • 分类:php · http-client · swoole · coroutine
  • 作者:Tom
  • 更新:2026-08-23

是什么

Saber 是基于 Swoole 协程的高性能 PHP HTTP 客户端,是 Swoole 人性化组件库的一员。底层基于 Swoole 原生协程 Client,提供了类似 Python requests 库 / JavaScript axios 的友好风格 API,同时兼容 PSR-7 标准。最大特点:用同步写法写异步高性能代码,业务层完全感知不到协程调度器的存在。

解决什么问题

传统 PHP 生态里,发 HTTP 请求的主流方案是 curl_* 系列函数,存在以下问题:

  • 同步阻塞:一个请求没返回,后续代码全等着。
  • 回调地狱:异步写法代码跳跃,逻辑断裂。
  • 配置繁琐:设置超时、重试、代理、Cookie,每样都要手写。
  • 长连接管理:手动维护连接池、复用连接。

Saber 用 Swoole 协程把上述问题全部在底层解决,暴露给业务层的接口和 requests 一样简单直观。

快速安装

# 依赖:PHP 7.1+,Swoole 2.1.2+(推荐 Swoole 4.x)
# 通过 Composer 安装
composer require swlib/saber

# 如需手动安装,下载 dist/humanize.min.js(注意这是 Saber 的发布产物,不是 HubSpot/humanize)

⚠️ Swoole 必须在 onRequestonReceiveonConnect 等事件回调函数中调用,或者用 go() 关键字包裹(Swoole 的 swoole.use_shortname 默认开启,简写 go 可用)。

核心用法

1. 全局静态方法(SaberGM)

不需要实例,直接调用,等价于 Python 的 requests

go(function () {
    echo SaberGM::get('http://httpbin.org/get');
    echo SaberGM::post('http://httpbin.org/post', ['foo' => 'bar']);
    echo SaberGM::put('http://httpbin.org/put', ['foo' => 'bar']);
    echo SaberGM::patch('http://httpbin.org/patch', ['foo' => 'bar']);
    echo SaberGM::delete('http://httpbin.org/delete');
});

⚠️ 所有 go() 必须在 Swoole 的协程环境内;裸跑 php script.php 需要配合 Swoole Server 或 Co\run() 包装。

2. 实例方式 + Base URI

适合配置公共参数(base_uri、headers 等)后复用:

$saber = Saber::create([
    'base_uri' => 'http://httpbin.org',
    'headers' => [
        'Accept-Language' => 'en,zh-CN;q=0.9,zh;q=0.8',
        'Content-Type' => ContentType::JSON,  // ContentType::JSON = 'application/json'
        'DNT' => '1',
        'User-Agent' => null                  // null = 不发 UA 头
    ]
]);

echo $saber->get('/get');
echo $saber->post('/post', ['foo' => 'bar']);
echo $saber->patch('/patch', ['foo' => 'bar']);
echo $saber->put('/put', ['foo' => 'bar']);
echo $saber->delete('/delete');

ContentType::JSON 等常量可查 Swlib\Http\ContentType 类。

创建会话实例后,Cookie 自动持久化,行为等同于浏览器:

$session = Saber::session([
    'base_uri' => 'http://httpbin.org',
    'redirect' => 0      // 关闭重定向,便于调试
]);

// 先设 Cookie
$session->get('/cookies/set?foo=bar&k=v&apple=banana');
// 再取,确认 Cookie 携带
echo $session->get('/cookies')->body;

⚠️ 并发重定向时,多个重定向请求并发发出而非队列串行,性能更优。

4. 多请求并发(requests)

一次发起多个请求,汇总结果:

$responses = SaberGM::requests([
    ['uri' => 'http://github.com/'],
    ['uri' => 'http://github.com/'],
    ['uri' => 'https://github.com/']
]);

echo "multi-requests [ {$responses->success_num} ok, {$responses->error_num} error ]:\n";
echo "consuming-time: {$responses->time}s\n";
// multi-requests [ 3 ok, 0 error ]:
// consuming-time: 0.79090881347656s

5. 数据解析(list)

支持 JSON / XML / HTML / URL-Query 四种格式快速解析:

[$json, $xml, $html] = SaberGM::list([
    'uri' => [
        'http://httpbin.org/get',
        'http://www.w3school.com.cn/example/xmle/note.xml',
        'http://httpbin.org/html'
    ]
]);

var_dump($json->getParsedJsonArray());
var_dump($xml->getParsedXmlArray(true));
var_dump($html->getParsedDomObject()->getElementsByTagName('h1')->item(0)->textContent);

6. HTTP / SOCKS5 代理

$uri = 'http://myip.ipip.net/';
echo SaberGM::get($uri, ['proxy' => 'http://127.0.0.1:1087'])->body;
echo SaberGM::get($uri, ['proxy' => 'socks5://127.0.0.1:1086'])->body;

7. 文件上传(多文件并发)

支持三种参数风格(string / array / object)混合上传:

$file1 = __DIR__ . '/black.png';

// 风格1:字符串路径
$file2 = [
    'path' => __DIR__ . '/black.png',
    'name' => 'white.png',
    'type' => ContentType::MAP['png'],
    'offset' => null,   // 断点续传用
    'size' => null      // 部分上传用
];

// 风格2:SwUploadFile 对象
$file3 = new SwUploadFile(__DIR__ . '/black.png', 'white.png', ContentType::MAP['png']);

echo SaberGM::post('http://httpbin.org/post', null, [
    'files' => [
        'image1' => $file1,
        'image2' => $file2,
        'image3' => $file3
    ]
]);

8. 超大文件下载(异步 + 断点续传)

// 底层协程调度,支持异步发送和断点续传
$saber->download('/large-file.zip', '/tmp/saved.zip', [
    'offset' => 0,    // 从 0 开始下载
    'size' => null     // null = 全文件
]);

9. 自动重试 + 超时配置

$saber = Saber::create([
    'base_uri' => 'https://api.example.com',
    'timeout' => 3000,      // 毫秒级超时
    'retry' => 3,           // 自动重试 3 次
    'retry_delay' => 1000    // 重试间隔 1 秒
]);

10. PSR-7 标准风格

完全兼容 PSR-7,可用标准接口链式调用:

use Swlib\SaberGM;
use Nyholm\Psr7\Uri;

$bufferStream = new BufferStream();
$bufferStream->write(json_encode(['foo' => 'bar']));

$response = SaberGM::psr()
    ->withMethod('POST')
    ->withUri(new Uri('http://httpbin.org/post?foo=bar'))
    ->withQueryParams(['foo' => 'option is higher-level than uri'])
    ->withHeader('content-type', ContentType::JSON)
    ->withBody($bufferStream)
    ->exec()->recv();

echo $response->getBody();

11. 连接池

模式 说明
无限连接池 请求来时自动创建连接,无上限
定容连接池 固定 N 个连接,满了排队
动态变容 根据负载自动扩缩容连接数

⚠️ 一次性脚本用完记得释放连接池,避免资源泄漏;长期运行进程(Swoole Server)则无需手动释放。

典型适用场景

  • PHP 爬虫:Saber 的 Cookie 管理 + 并发请求 + 代理支持,是爬虫项目的理想底层。
  • API 代理服务:用 Saber 快速搭建 API 转发/鉴权中间层,支持 session 保持。
  • 微服务间 HTTP 调用:Swoole 环境下,高并发 HTTP 客户端比 Guzzle 更轻量。
  • Webhook 消费者:配合 Swoole HTTP Server,消费外部 Webhook 并调用内部服务。
  • 大文件上传/下载:断点续传 + 异步非阻塞,适合媒体类服务。

坑与注意

坑点 说明
必须在 Swoole 协程环境运行 php script.php 不会工作,需要 go()Co\run() 包装
Swoole 版本依赖 最低 Swoole 2.1.2(发布于 2017 年),但推荐 Swoole 4.x;需确认你的 PHP 扩展环境
PHP 7.1 基础语法 composer require 默认拉最新 master,可能需要 swlib/saber:dev-master 指定版本
HTTP/2 未支持 README 明确说 HTTP/2 在 Roadmap,暂无计划;如需 HTTP/2 客户端,考虑 php-http/guzzle + Swoole 适配器
中文文档依赖机翻 英文 README 内容更完整;中文文档部分段落为自动翻译,可能有歧义
IDE Helper 需要单独安装 官方提供 IDE Helper 包,写代码时自动补全;不装则无提示
连接池在 Swoole Task/Worker 间不共享 协程级别的连接池,不会跨 Swoole Worker 共享数据

与同类对比

工具 语言 协程 HTTP/2 PSR-7 适用场景
Saber PHP ✅ Swoole 原生 ❌ Roadmap ✅ 完整兼容 Swoole 环境高并发 HTTP
Guzzle PHP ❌(需 react/guzzle-adapter) 通用 PHP HTTP 场景
PHP cURL PHP ⚠️ 部分 最基础场景
httpx Python ✅(asyncio) Python 异步 HTTP
requests Python Python 同步 HTTP

Saber 在 PHP 生态的差异化优势是高性能 + 易用性兼得:基于 Swoole 的协程调度天然支持高并发,而 API 风格又比 Guzzle + Swoole Adapter 的组合简洁很多。

一句话推荐结论

如果你在 Swoole 环境下需要一个高性能 HTTP 客户端,Saber 的 API 设计友好、Cookie/重试/代理/并发开箱即用,值得直接上手——唯一需要确认的是你的 Swoole 版本 ≥ 4.x 且项目允许引入协程依赖。