gokure/http-client

此包已被弃用且不再维护。未建议替代包。

围绕 Guzzle HTTP 客户端的 Hyperf 的一个表达性、最小化 API。

v1.1.1 2021-11-11 11:32 UTC

This package is auto-updated.

Last update: 2023-05-11 14:57:10 UTC


README

通过 laravel/framework 实现 Hyperf 的 HTTP 客户端。

介绍

HTTP 客户端是一个围绕 Guzzle HTTP 客户端(来自 Laravel)的表达性、最小化 API,允许您快速发出 HTTP 请求以与其他 Web 应用程序进行通信。

在开始之前,您应确保已将 Guzzle 包作为应用程序的依赖项安装。默认情况下,Hyperf 自动包含此依赖项。但是,如果您之前已移除该包,您可以通过 Composer 再次安装它。

composer require guzzlehttp/guzzle

安装

在您的 composer.json 中要求 gokure/http-client 包并更新您的依赖项

composer require gokure/http-client

发出请求

要发出请求,您可以使用 Http 门面提供的 getpostputpatchdelete 方法。首先,让我们看看如何向另一个 URL 发出基本的 GET 请求

use Gokure\Http\Client\Http;

$response = Http::get('http://example.com');

get 方法返回一个 Gokure\Http\Client 实例,该实例提供各种方法,可用于检查响应

$response->body() : string;
$response->json() : array|mixed;
$response->collect() : Hyperf\Utils\Collection;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->failed() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;

Gokure\Http\Client\Response 对象还实现了 PHP 的 ArrayAccess 接口,允许您直接在响应上访问 JSON 响应数据

return Http::get('http://example.com/users/1')['name'];

请求转储

如果您希望在发送之前转储发出请求的实例并终止脚本的执行,您可以在请求定义的开始处添加 dd 方法

return Http::dd()->get('http://example.com');

请求数据

当然,在发出 POSTPUTPATCH 请求时发送额外的数据是很常见的,因此这些方法接受一个数组作为它们的第二个参数。默认情况下,数据将使用 application/json 内容类型发送

use Gokure\Http\Client\Http;

$response = Http::post('http://example.com/users', [
    'name' => 'Steve',
    'role' => 'Network Administrator',
]);

GET 请求查询参数

在发出 GET 请求时,您可以直接将查询字符串附加到 URL 上,或者将键/值对的数组作为 get 方法的第二个参数传递

$response = Http::get('http://example.com/users', [
    'name' => 'Taylor',
    'page' => 1,
]);

发送表单 URL 编码请求

如果您想使用 application/x-www-form-urlencoded 内容类型发送数据,您应该在发出请求之前调用 asForm 方法

$response = Http::asForm()->post('http://example.com/users', [
    'name' => 'Sara',
    'role' => 'Privacy Consultant',
]);

发送原始请求体

如果您在发出请求时想提供原始请求体,您可以使用 withBody 方法。内容类型可以通过方法的第二个参数提供

$response = Http::withBody(
    base64_encode($photo), 'image/jpeg'
)->post('http://example.com/photo');

多部分请求

如果您想以多部分请求发送文件,您应在发送请求之前调用attach方法。此方法接受文件的名称及其内容。如果需要,您还可以提供一个第三个参数,该参数将被视为文件的名称

$response = Http::attach(
    'attachment', file_get_contents('photo.jpg'), 'photo.jpg'
)->post('http://example.com/attachments');

您可以选择传递一个流资源而不是文件的原始内容

$photo = fopen('photo.jpg', 'r');

$response = Http::attach(
    'attachment', $photo, 'photo.jpg'
)->post('http://example.com/attachments');

头部信息

可以使用withHeaders方法向请求添加头部信息。此withHeaders方法接受一个键/值对的数组

$response = Http::withHeaders([
    'X-First' => 'foo',
    'X-Second' => 'bar'
])->post('http://example.com/users', [
    'name' => 'Taylor',
]);

认证

您可以使用withBasicAuthwithDigestAuth方法分别指定基本和摘要认证凭据

// Basic authentication...
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(...);

// Digest authentication...
$response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(...);

令牌

如果您想快速将令牌添加到请求的Authorization头部,可以使用withToken方法

$response = Http::withToken('token')->post(...);

超时

可以使用timeout方法指定等待响应的最大秒数

$response = Http::timeout(3)->get(...);

如果超出了给定的时间,将抛出一个Gokure\Http\Client\ConnectionException实例。

重试

如果您想使HTTP客户端在发生客户端或服务器错误时自动重试请求,可以使用retry方法。该retry方法接受两个参数:请求应该尝试的最大次数和Hyperf应在尝试之间等待的毫秒数

$response = Http::retry(3, 100)->post(...);

如果所有请求都失败,将抛出一个Gokure\Http\Client\RequestException实例。

错误处理

与Guzzle的默认行为不同,Hyperf的HTTP客户端包装器在客户端或服务器错误(来自服务器的400500级响应)时不会抛出异常。您可以使用successfulclientErrorserverError方法确定是否返回了这些错误之一

// Determine if the status code is >= 200 and < 300...
$response->successful();

// Determine if the status code is >= 400...
$response->failed();

// Determine if the response has a 400 level status code...
$response->clientError();

// Determine if the response has a 500 level status code...
$response->serverError();

抛出异常

如果您有一个响应实例,并且当响应状态码指示客户端或服务器错误时,想抛出一个Gokure\Http\Client\RequestException实例,可以使用throw方法

$response = Http::post(...);

// Throw an exception if a client or server error occurred...
$response->throw();

return $response['user']['id'];

Gokure\Http\Client\RequestException实例有一个公开的$response属性,这允许您检查返回的响应。

throw方法在没有错误发生的情况下返回响应实例,允许您将其他操作链接到throw方法

return Http::post(...)->throw()->json();

如果您想在抛出异常之前执行一些额外的逻辑,可以将闭包传递给throw方法。在调用闭包后,将自动抛出异常,因此您不需要在闭包内部重新抛出异常

return Http::post(...)->throw(function ($response, $e) {
    //
})->json();

Guzzle选项

您可以使用withOptions方法指定额外的Guzzle请求选项。该方法接受一个键/值对的数组

$response = Http::withOptions([
    'debug' => true,
])->get('http://example.com/users');

并发请求

有时,您可能希望并发地发出多个HTTP请求。换句话说,您希望同时分发多个请求,而不是按顺序发出请求。这在与缓慢的HTTP API交互时可以带来显著的性能改进。

幸运的是,您可以使用pool方法完成这项操作。该方法接受一个闭包,该闭包接收一个Gokure\Http\Client\Pool实例,允许您轻松地将请求添加到请求池中以进行调度。

use Gokure\Http\Client\Pool;
use Gokure\Http\Client\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->get('https:///first'),
    $pool->get('https:///second'),
    $pool->get('https:///third'),
]);

return $responses[0]->ok() &&
       $responses[1]->ok() &&
       $responses[2]->ok();

如您所见,每个响应实例都可以根据其添加到池中的顺序进行访问。如果您愿意,可以使用as方法为请求命名,这样您就可以通过名称访问相应的响应。

use Gokure\Http\Client\Pool;
use Gokure\Http\Client\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('first')->get('https:///first'),
    $pool->as('second')->get('https:///second'),
    $pool->as('third')->get('https:///third'),
]);

return $responses['first']->ok();

测试

许多Hyperf服务提供功能,帮助您轻松且具有表达性地编写测试,Hyperf的HTTP包装器也不例外。HTTP外观的fake方法允许您指示HTTP客户端在请求时返回存根/模拟响应。

模拟响应

例如,要指示HTTP客户端为每个请求返回空或200状态码的响应,您可以不带参数调用fake方法。

use Gokure\Http\Client\Http;

Http::fake();

$response = Http::post(...);

{note} 当模拟请求时,HTTP客户端中间件不会执行。您应该定义对模拟响应的预期,就像这些中间件已经正确运行一样。

模拟特定URL

或者,您可以将一个数组传递给fake方法。数组的键应表示您希望模拟的URL模式及其相关响应。可以使用*字符作为通配符。对未模拟的URL发出的任何请求实际上都会执行。您可以使用HTTP外观的response方法为这些端点构建存根/模拟响应。

Http::fake([
    // Stub a JSON response for GitHub endpoints...
    'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers),

    // Stub a string response for Google endpoints...
    'google.com/*' => Http::response('Hello World', 200, $headers),
]);

如果您希望指定一个后备URL模式,该模式将模拟所有不匹配的URL,您可以使用单个*字符。

Http::fake([
    // Stub a JSON response for GitHub endpoints...
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // Stub a string response for all other endpoints...
    '*' => Http::response('Hello World', 200, ['Headers']),
]);

模拟响应序列

有时您可能需要指定单个URL应按特定顺序返回一系列模拟响应。您可以使用Http::sequence方法构建响应以实现这一点。

Http::fake([
    // Stub a series of responses for GitHub endpoints...
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->pushStatus(404),
]);

当响应序列中的所有响应都已消费后,任何进一步的请求将导致响应序列抛出异常。如果您希望指定在序列为空时应返回的默认响应,您可以使用whenEmpty方法。

Http::fake([
    // Stub a series of responses for GitHub endpoints...
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->whenEmpty(Http::response()),
]);

如果您想要模拟一系列响应,但不需要指定应模拟的具体URL模式,您可以使用Http::fakeSequence方法。

Http::fakeSequence()
        ->push('Hello World', 200)
        ->whenEmpty(Http::response());

模拟回调

如果您需要更复杂的逻辑来确定对某些端点返回哪些响应,您可以将闭包传递给fake方法。此闭包将接收一个Gokure\Http\Client\Request实例,并应返回一个响应实例。在您的闭包中,您可以执行必要的任何逻辑来确定应返回哪种类型的响应。

Http::fake(function ($request) {
    return Http::response('Hello World', 200);
});

检查请求

在模拟响应时,您有时可能希望检查客户端接收到的请求,以确保您的应用程序正在发送正确的数据或头信息。您可以通过在调用Http::fake后调用Http::assertSent方法来实现这一点。

assertSent 方法接受一个闭包,该闭包将接收一个 Gokure\Http\Client\Request 实例,并应返回一个布尔值,表示请求是否符合您的期望。为了使测试通过,至少必须发送一个符合给定期望的请求。

use Gokure\Http\Client\Request;
use Gokure\Http\Client\Http;

Http::fake();

Http::withHeaders([
    'X-First' => 'foo',
])->post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertSent(function (Request $request) {
    return $request->hasHeader('X-First', 'foo') &&
           $request->url() == 'http://example.com/users' &&
           $request['name'] == 'Taylor' &&
           $request['role'] == 'Developer';
});

如果需要,您可以使用 assertNotSent 方法断言未发送特定的请求

use Gokure\Http\Client\Request;
use Gokure\Http\Client\Http;

Http::fake();

Http::post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertNotSent(function (Request $request) {
    return $request->url() === 'http://example.com/posts';
});

或者,您可以使用 assertNothingSent 方法来断言在测试期间未发送任何请求

Http::fake();

Http::assertNothingSent();

许可证

在 MIT 许可证下发布,请参阅 LICENSE