amphp/http-client

一个针对 PHP 的高级异步 HTTP 客户端库,支持高效、非阻塞和并发请求和响应。

资助包维护!
amphp

安装次数: 3,099,993

依赖者: 110

建议者: 3

安全性: 3

星标: 701

关注者: 33

分支: 67

开放问题: 13

v5.1.0 2024-04-21 16:40 UTC

README

AMPHP 是一个为 PHP 设计的包含事件驱动库的集合,它考虑了纤维和并发性。本包提供了一个基于 Revolt 的 PHP 异步 HTTP 客户端。它的 API 简化了符合标准的 HTTP 资源遍历和 RESTful 网络服务消费,而不会掩盖底层协议。该库手动实现了通过 TCP 套接字的 HTTP;因此,它不依赖于 ext/curl

功能

安装

此包可以作为 Composer 依赖项安装。

composer require amphp/http-client

此外,您可能还想安装 nghttp2 库,利用 FFI 加速并减少内存使用。

使用方法

与此库的主要交互点是 HttpClient 类。可以使用 HttpClientBuilder 构建实例,而不必了解现有实现。

HttpClientBuilder 允许注册两种类型的 拦截器,这允许以可组合的方式定制 HttpClient 的行为。

在其最简单形式中,HTTP 客户端接受一个包含 URL 的请求作为字符串,并将其解释为对该资源的 GET 请求,没有任何自定义头信息。如果不存在,将自动添加标准头信息如 AcceptConnectionHost

use Amp\Http\Client\HttpClientBuilder;

$client = HttpClientBuilder::buildDefault();

$response = $client->request(new Request("https://httpbin.org/get"));

var_dump($response->getStatus());
var_dump($response->getHeaders());
var_dump($response->getBody()->buffer());

请求

HttpClient 需要将 Request 作为第一个参数传递给 request()。可以使用 Request 类来指定请求的更多具体信息,例如设置头信息或更改请求方法。

注意 Request 对象是可变的(与 amphp/artax / PSR-7 中的不可变对象不同)。

克隆 Request 对象会导致深度克隆,但这通常仅在请求需要重试或克隆为子请求时才需要。

请求 URI

构造函数需要一个绝对请求 URI。使用 Request::setUri(string $uri) 允许更改请求 URI。

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");
$request->setUri("https://google.com/");

Request::getUri() 暴露了给定 Request 对象的请求 URI。

请求方法

构造函数接受一个可选的请求方法,默认为 GET。使用 Request::setMethod(string $method) 允许更改请求方法。

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");
$request->setMethod("PUT");

Request::getMethod() 暴露了给定 Request 对象的请求方法。

请求头信息

Request::setHeader(string $field, string $value) 允许更改请求头。这将移除该字段的任何先前值。Request::addHeader(string $field, string $value) 允许添加额外的头行,而不会删除现有行。

Request::setHeaders(array $headers) 允许一次性添加多个头,数组的键是字段名,值是头值。头值也可以是字符串数组,以设置多个头行。

Request::hasHeader(string $field) 检查是否存在具有给定名称的至少一个头行。

Request::getHeader(string $field) 返回具有给定名称的第一个头行或 null 如果不存在这样的头。

Request::getHeaderArray(string $field) 返回具有给定名称的头行数组。如果没有具有给定名称的头,则返回空数组。

Request::getHeaders() 返回一个关联数组,键是头名称,值是头行数组。

$request = new Request("https://httpbin.org/post", "POST");
$request->setHeader("X-Foobar", "Hello World");
$request->setBody("foobar");

请求正文

Request::setBody($body) 允许更改请求正文。接受类型是 stringnullHttpContentstringnull 将自动转换为 HttpContent 实例。

注意 HttpContent 主要是请求正文的一个工厂。我们在这里不能简单地接受流,因为请求正文可能需要在重定向/重试时再次发送。

$request = new Request("https://httpbin.org/post", "POST");
$request->setBody("foobar");

Request::getBody() 揭示了给定 Request 对象的请求正文,并且总是会返回一个 HttpContent

响应

HttpClient::request() 一旦成功接收到响应头,就会返回一个 Response

注意 Response 对象是可变的(与 Artax v3 / PSR-7 中的不可变不同)

响应状态

您可以使用 getStatus() 获取响应的 HTTP 状态。它返回一个整数。与状态相关的可选(可能为空)原因可以通过 getReason() 获取。

$response = $client->request($request);

var_dump($response->getStatus(), $response->getReason());

响应协议版本

您可以使用 getProtocolVersion() 获取响应的 HTTP 协议版本。

$response = $client->request($request);

var_dump($response->getProtocolVersion());

响应头

响应头可以通过一系列方法访问。

  • hasHeader(string) 返回是否有一个给定的头存在。
  • getHeader(string) 返回第一个具有给定名称的头或 null 如果不存在这样的头。
  • getHeaderArray(string) 返回所有具有给定名称的头,可能是一个空数组。
  • getHeaders() 返回所有头作为关联数组,见下文。

getHeaders() 格式

[
    "header-1" => [
        "value-1",
        "value-2",
    ],
    "header-2" => [
        "value-1",
    ],
]

响应正文

getBody() 返回一个 Payload,它允许简单的缓冲和流访问。

警告 $chunk = $response->getBody()->read(); 只从正文读取一个块,而 $contents = $response->getBody()->buffer() 缓存整个正文。有关更多信息,请参阅 Payload 文档

请求、原始请求和上一个响应

getRequest() 允许访问与响应对应的请求。在这种情况下,它可能不是原始请求,因为在重定向的情况下。 getOriginalRequest() 返回客户端发送的原始请求。这可能与传递给 Client::request() 的请求不同,因为客户端可能规范化头或分配cookie。 getPreviousResponse 允许在重定向的情况下访问上一个响应,但这些响应的正文将不可用,因为它们被丢弃。如果您需要访问这些,您需要禁用自动重定向并自行实现。

拦截器

拦截器允许以可组合的方式自定义HttpClient的行为。用例范围从添加/删除请求/响应头和记录时间信息到更高级的用例,例如完全符合规范的HTTP缓存,该缓存拦截请求并在可能的情况下从缓存中提供服务。

use Amp\Http\Client\Client;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Interceptor\SetRequestHeader;
use Amp\Http\Client\Interceptor\SetResponseHeader;
use Amp\Http\Client\Request;

$client = (new HttpClientBuilder)
    ->intercept(new SetRequestHeader('x-foo', 'bar'))
    ->intercept(new SetResponseHeader('x-tea', 'now'))
    ->build();

$response = $client->request(new Request("https://httpbin.org/get"));
$body = $response->getBody()->buffer();

存在两种拦截器,分别具有名为ApplicationInterceptorNetworkInterceptor的独立接口。

选择正确的拦截器

大多数拦截器应该实现为ApplicationInterceptor。然而,有时需要访问底层连接属性。在这种情况下,可以实现NetworkInterceptor来访问使用的IP和TLS设置。

实现NetworkInterceptor的另一个用例是,该拦截器仅在请求通过网络发送而不是从缓存或类似服务中提供时运行。然而,这通常可以通过应用程序拦截器的配置顺序来解决。

网络拦截器的主要缺点是它们必须相当快,不能太慢,因为它们仅在连接创建后调用,客户端如果在合理时间内没有活动,将会遇到超时。

拦截器列表

  • 添加请求头
  • 添加响应头
  • 条件拦截器
  • 解压缩响应
  • 遵循重定向
  • 禁止URI用户信息
  • 如果来源
  • 修改请求
  • 修改响应
  • 删除请求头
  • 删除响应头
  • 重试请求
  • 设置请求头
  • 如果未设置则设置请求头
  • 设置响应头
  • 如果未设置则设置响应头
  • 设置请求超时
  • Cookie处理程序
  • 私有缓存

重定向

如果你使用HttpClientBuilder,默认情况下,生成的HttpClient将自动跟进多达十个重定向。可以使用HttpClientBuilder::followRedirects()自定义或禁用自动跟进(使用0作为限制)。

重定向策略

FollowRedirects拦截器只会遵循使用GET方法的重定向。如果使用其他请求方法并收到307308响应,则直接返回该响应。跨源重定向将尝试不设置任何头信息,因此任何应用程序头将被丢弃。如果使用HttpClientBuilder配置客户端,则FollowRedirects拦截器是最外层的拦截器,因此由拦截器设置的任何头信息仍然存在于响应中。因此,建议通过拦截器设置头信息,而不是直接在请求中设置。

检查重定向链

所有之前的响应都可以通过结果ResponseResponse::getPreviousResponse()访问。然而,在重定向中,响应体会被丢弃,因此无法再次消费。如果您想消费重定向响应体,则需要实现自己的拦截器。

cookies

请参阅amphp/http-client-cookies

日志记录

LogHttpArchive事件监听器允许将所有请求/响应以及详细的时间信息记录到HTTP存档(HAR)

然后可以将这些日志文件导入浏览器的开发者工具或类似HTTP存档查看器Google的HAR分析器的在线工具。

警告 如果您可能提交的日志文件包含敏感信息(例如URL或头信息),请小心处理。

use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\EventListener\LogHttpArchive;

$httpClient = (new HttpClientBuilder)
    ->listen(new LogHttpArchive('/tmp/http-client.har'))
    ->build();

$httpClient->request(...);

HAR Viewer Screenshot

代理

请参阅 amphp/http-tunnel

版本管理

amphp/http-client 与所有其他 amphp 包一样,遵循 semver 语义化版本规范。

所有在 Internal 命名空间中或在代码中标有 @internal 的内容都不是公共 API,因此不受向后兼容保证的覆盖。

安全性

如果您发现任何与安全相关的问题,请通过电子邮件 [email protected] 联系,而不是使用问题跟踪器。

许可证

MIT 许可证(MIT)。更多信息请参阅 LICENSE