PHP code example of yunadmin / http-client
1. Go to this page and download the library: Download yunadmin/http-client library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
yunadmin / http-client example snippets
use Yunadmin\HttpClient\Client;
$client = new Client([
'base_uri' => 'https://api.example.com/v1/',
'timeout' => 5.0, // 总超时(秒,支持小数)
'headers' => ['Accept' => 'application/json'],
]);
// GET + query
$resp = $client->get('users/123', ['query' => ['
$client = new Client();
$client->head('https://example.com');
$client->post('https://api.example.com/items', ['json' => ['name'=>'x']]);
$client->put('https://api.example.com/items/1', ['json' => ['name'=>'y']]);
$client->patch('https://api.example.com/items/1',['json' => ['name'=>'z']]);
$client->delete('https://api.example.com/items/1');
$client->options('https://api.example.com/');
$resp = $client->post('https://api.example.com/articles', [
'json' => ['title' => '你好', 'tags' => ['php','http']],
'headers' => ['X-Trace' => 'abc'],
]);
// 自动:Content-Type: application/json + json_encode
$client->post('https://sso.example.com/login', [
'form_params' => [
'username' => 'admin',
'password' => '123456',
'remember' => 1,
],
]);
// Content-Type: application/x-www-form-urlencoded
$client->post('https://cdn.example.com/upload', [
'multipart' => [
[
'name' => 'avatar',
'contents' => fopen(__DIR__ . '/face.png', 'r'),
'filename' => 'face.png',
'headers' => ['Content-Type' => 'image/png'],
],
[
'name' => 'album',
'contents' => fopen(__DIR__ . '/album.zip', 'r'),
'filename' => 'album.zip',
],
[
'name' => 'desc',
'contents' => '我的头像 & 相册',
],
],
]);
// 字符串
$client->post('https://api.example.com/raw', [
'body' => '任何原始字节...',
'headers' => ['Content-Type' => 'text/plain'],
]);
// 大文件 — 使用 LazyOpenStream,按需打开、流式发送
use function Yunadmin\HttpClient\lazy_open_stream;
$body = lazy_open_stream('/data/huge.zip', 'r');
$client->post('https://cdn.example.com/upload', [
'body' => $body,
'headers' => ['Content-Type' => 'application/zip'],
]);
$client = new Client(['base_uri' => 'https://api.example.com/v1/']);
// 注意 base_uri 以 / 结尾,否则把相对 uri 当作 path 拼接
$client->get('users'); // → /v1/users
$client->get('/users'); // → /users (以 / 开头会覆盖 path)
$client->get('https://other.com/x'); // → 完整 URI,忽略 base_uri
$client->get('https://api.example.com/search', [
'query' => ['q' => 'php 8', 'page' => 1, 'tags' => ['a','b']],
]);
// 自动 http_build_query,也支持自己传字符串:'q=php+8&page=1'
use Yunadmin\HttpClient\Uri;
$u = new Uri('https://user:[email protected] :8443/v1?q=1#frag');
echo $u->getScheme(); // https
echo $u->getHost(); // api.example.com
echo $u->getPort(); // 8443
echo $u->getPath(); // /v1
echo $u->getQuery(); // q=1
echo $u->getUserInfo(); // user:pass
echo (string)$u->withScheme('http')->withPort(null)->withQuery('x=2');
// → http://user:[email protected] /v1?x=2#frag
$client = new Client([
// 1. Basic / Digest / Bearer / 自定义
'auth' => ['user', 'pass'], // Basic
//'auth' => ['user', 'pass', 'digest'], // Digest(cURL 支持)
//'auth' => ['xxxxxxxx-token', '', 'bearer'], // Bearer
//'auth' => 'Basic dXNlcjpwYXNz', // 直接写字符串
// 2. 超时
'timeout' => 10.0, // 总超时秒(支持小数)
'connect_timeout' => 2.0, // 连接超时秒
// 3. 强制 IP 版本
//'force_ip_resolve' => 'v4', // 'v4' | 'v6' | null
// 4. TLS
'verify' => true, // 默认 true,校验证书
//'verify' => '/etc/ssl/certs/ca-bundle.crt', // CA 路径
//'cert' => '/path/client.crt', // 客户端证书
//'ssl_key' => '/path/client.key', // 客户端私钥
// 5. 代理
//'proxy' => 'http://127.0.0.1:8080', // 单个
// 或按 scheme 分别设置
//'proxy' => [
// 'http' => 'http://10.0.0.1:8080',
// 'https' => 'http://10.0.0.1:8443',
// 'no' => ['.intranet.local', 'localhost'],
//],
// 6. 解压缩
'decode_content' => true, // 默认 true:加 Accept-Encoding,并自动 gzip/deflate 解响应体
]);
$client = new Client();
$f1 = $client->getAsync('https://example.com/a');
$f2 = $client->getAsync('https://example.com/b');
$f3 = $client->postAsync('https://example.com/c', ['json' => ['k' => 'v']]);
// 阻塞等到各自完成(内部 tick Multi,三条是并发的)
$r1 = $f1->wait();
$r2 = $f2->wait();
$r3 = $f3->wait();
$client
->getAsync('https://api.example.com/items/1')
->then(static fn($resp) => $resp->getJsonBody()) // 成功:转换
->then(static fn($data) => process($data)) // 继续转
->otherwise(static fn(\Throwable $e) => log($e)) // 失败兜底
->wait();
$urls = [
'https://example.com/p1',
'https://example.com/p2',
'https://example.com/p3',
// ... 可几百上千条
];
$requests = [];
foreach ($urls as $u) {
$requests[] = ['GET', $u];
}
$client->pool($requests, [
'concurrency' => 10, // 同时最多 10 条
'fulfilled' => static function ($resp, $index) use ($urls) {
echo "[OK] #{$index} {$urls[$index]} => {$resp->getStatusCode()}\n";
},
'rejected' => static function (\Throwable $e, $index) use ($urls) {
echo "[ERR] #{$index} {$urls[$index]} => {$e->getMessage()}\n";
},
]);
$client = new Client([
'allow_redirects' => [
'max' => 5, // 最大重定向次数
'strict' => true, // 严格模式:302/303 POST → 改 GET;false 保持原方法
'keep_body' => false, // 重定向后是否保留 body
],
]);
// 或简单关闭:
// $client = new Client(['allow_redirects' => false]);
use Yunadmin\HttpClient\Exception\ClientException;
use Yunadmin\HttpClient\Exception\ServerException;
use Yunadmin\HttpClient\Exception\RequestException;
try {
$client->get('https://api.example.com/404-thing');
} catch (ClientException $e) { // 4xx
echo "4xx: " . $e->getResponse()?->getStatusCode();
} catch (ServerException $e) { // 5xx
echo "5xx: " . $e->getResponse()?->getStatusCode();
} catch (RequestException $e) { // 基类(含连接失败等)
echo "req failed: " . $e->getMessage();
}
$client = new Client([
'retry' => [
'retries' => 3, // 最多重试 3 次(共 1 + 3 = 4 次请求)
'delay' => 300, // 初始延迟 ms
'multiplier' => 2.0, // 2 次幂退避:300 → 600 → 1200 ms
// 'when' 可选:callable(次数, Request, Response?, e?) : bool
// 未传时,默认:连接错误重试;5xx 重试;幂等方法的 429/503 重试
],
]);
use Yunadmin\HttpClient\Cookie\CookieJar;
$jar = new CookieJar($strictMode = true);
$client = new Client(['cookies' => $jar]);
// 1. 登录,Set-Cookie 自动写入 $jar
$client->post('https://sso.example.com/login', [
'form_params' => ['u' => 'admin', 'p' => '123456'],
]);
// 2. 后续请求自动带上匹配的 Cookie
$me = $client->get('https://sso.example.com/me')->getJsonBody();
$jar->set($name, $value, ['domain'=>'example.com','path'=>'/','secure'=>true,'expires'=>time()+3600]);
$jar->get('session_id', 'example.com', '/'); // Cookie 对象或 null
$jar->toArray(); // 导出数组
$jar->toHeaderString('https://api.example.com/x'); // 给某个 URL 拼 Cookie 请求头
$client->get('https://example.com/x', [
'cookies' => ['sid' => 'abc'], // array → 转 k=v
//'cookies' => 'sid=abc; other=xyz', // string → 直接 Cookie 头
]);
// 直接写文件路径
$client->get('https://example.com/big.zip', [
'sink' => __DIR__ . '/tmp/big.zip',
]);
// 或写已打开的资源流
$fp = fopen('php://temp', 'w+b');
$client->get('https://example.com/x', ['sink' => $fp]);
rewind($fp);
echo stream_get_contents($fp);
fclose($fp);
$client->get('https://example.com', [
'on_stats' => static function (object $s) {
echo "url: " . $s->url . "\n";
echo "status: " . ($s->response?->getStatusCode() ?? '-') . "\n";
echo "time(s): " . $s->time . "\n";
if (isset($s->handler_data)) {
// cURL: curl_getinfo 结果数组
// Stream: 包含 dns/connect/starttransfer/ttfb_ms 等分段耗时(毫秒)
}
},
]);
$client->get('https://example.com', [
'debug' => true, // 输出到 stdout
//'debug' => fopen('trace.log', 'ab'), // 写文件
]);
use function Yunadmin\HttpClient\http_get;
use function Yunadmin\HttpClient\http_post;
use function Yunadmin\HttpClient\http_json;
$html = http_get('https://example.com'); // 直接 string body
$html2 = http_post('https://example.com/form', ['a' => 1]); // application/x-www-form-urlencoded
$data = http_json('https://api.example.com/items'); // 自动 json_decode → array/stdClass
$resp = http_json('https://api.example.com/items', true); // true = 返回 Response 对象
use Yunadmin\HttpClient\Client;
use Yunadmin\HttpClient\Handler\HandlerStack;
use Yunadmin\HttpClient\Handler\MockHandler;
use Yunadmin\HttpClient\Middleware\HistoryMiddleware;
use Yunadmin\HttpClient\Response;
// 1. 准备响应队列
$mock = new MockHandler();
$mock->append(new Response(200, ['Content-Type' => 'application/json'], '{"id":1,"name":"a"}'));
$mock->append(new Response(201, ['X-Id' => '2'], ''));
$mock->append(new \RuntimeException('Network down')); // 也可以排队 Exception
// 2. 建 HandlerStack,推送 HistoryMiddleware
$history = [];
$stack = HandlerStack::createWithMock($mock);
$stack->push(new HistoryMiddleware($history), 'history');
// 3. 业务代码里注入 client,不发真实请求
$client = new Client(['handler' => $stack, 'base_uri' => 'https://api.example.com/']);
$a = $client->get('items/1')->getJsonBody();
$b = $client->post('items', ['json' => ['name' => 'x']]);
try {
$client->get('items/3');
} catch (\RuntimeException $e) {
// Net down
}
// 4. 断言
echo $history[0]['request']->getMethod(); // GET
echo $history[0]['request']->getUri(); // https://api.example.com/items/1
echo $history[0]['response']->getStatusCode();// 200
echo $history[1]['request']->getMethod(); // POST
echo $history[1]['options']['json']['name']; // x
echo count($history); // 3
use Yunadmin\HttpClient\Handler\HandlerStack;
use Yunadmin\HttpClient\Contract\RequestInterface;
use Yunadmin\HttpClient\Response;
$stack = HandlerStack::create(); // 自动挑 CurlHandler / StreamHandler
$stack->push(static function (callable $next) {
return static function (RequestInterface $req, array $opts) use ($next) {
// 进入:加 trace header
$req = $req->withHeader('X-Trace-Id', bin2hex(random_bytes(8)));
$t1 = microtime(true);
// 交给下一层
$result = $next($req, $opts);
// 出来:打点(支持同步 Response 或异步 Future)
$log = static function ($r) use ($t1, $req) {
$ms = round((microtime(true) - $t1) * 1000, 1);
$code = $r instanceof Response ? $r->getStatusCode() : 'ERR';
file_put_contents('request.log', "{$req->getMethod()} {$req->getUri()} => {$code} ({$ms}ms)\n", FILE_APPEND);
return $r;
};
if ($result instanceof \Yunadmin\HttpClient\Future) {
return $result->then($log, $log);
}
return $log($result);
};
}, 'trace');
$client = new Client(['handler' => $stack]);
$client->get('https://example.com');