Laravel HTTP 客户端
简介
Laravel 围绕 Guzzle HTTP 客户端提供了一套表达清晰、精简的 API,使你能够快速发出 HTTP 请求,与其他 Web 应用通信。Laravel 对 Guzzle 的封装专注于最常见的使用场景,并提供良好的开发体验。
发起请求
你可以使用 Http 门面提供的 head、get、post、put、patch 和 delete 方法发起请求。首先来看如何向另一个 URL 发出基本的 GET 请求:
use Illuminate\Support\Facades\Http;
$response = Http::get('http://example.com');
get 方法返回 Illuminate\Http\Client\Response 实例。该实例提供多种方法,可用于检查响应:
$response->body() : string;
$response->json($key = null, $default = null, $flags = null) : mixed;
$response->object() : object;
$response->collect($key = null) : Illuminate\Support\Collection;
$response->resource() : resource;
$response->status() : int;
$response->successful() : bool;
$response->redirect(): bool;
$response->failed() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;
Illuminate\Http\Client\Response 对象还实现了 PHP 的 ArrayAccess 接口,因此可以直接通过响应对象访问 JSON 响应数据:
return Http::get('http://example.com/users/1')['name'];
除了上述响应方法,你还可以使用以下方法判断响应是否具有特定的状态码:
$response->ok() : bool; // 200 OK
$response->created() : bool; // 201 Created
$response->accepted() : bool; // 202 Accepted
$response->noContent() : bool; // 204 No Content
$response->movedPermanently() : bool; // 301 Moved Permanently
$response->found() : bool; // 302 Found
$response->badRequest() : bool; // 400 Bad Request
$response->unauthorized() : bool; // 401 Unauthorized
$response->paymentRequired() : bool; // 402 Payment Required
$response->forbidden() : bool; // 403 Forbidden
$response->notFound() : bool; // 404 Not Found
$response->requestTimeout() : bool; // 408 Request Timeout
$response->conflict() : bool; // 409 Conflict
$response->unprocessableEntity() : bool; // 422 Unprocessable Entity
$response->tooManyRequests() : bool; // 429 Too Many Requests
$response->serverError() : bool; // >= 500 Server Error
URI 模板
HTTP 客户端也支持按照 URI 模板规范构造请求 URL。使用 withUrlParameters 方法,可以定义 URI 模板能够展开的 URL 参数:
Http::withUrlParameters([
'endpoint' => 'https://laravel.com',
'page' => 'docs',
'version' => '13.x',
'topic' => 'validation',
])->get('{+endpoint}/{page}/{version}/{topic}');
输出请求信息并终止执行
如果希望在发送请求前输出即将发出的请求实例,并终止脚本执行,可以在请求定义的开头加入 dd 方法:
return Http::dd()->get('http://example.com');
请求数据
发出 POST、PUT 和 PATCH 请求时,通常需要随请求发送额外数据,因此这些方法接受数据数组作为第二个参数。默认使用 application/json 内容类型发送数据:
use Illuminate\Support\Facades\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,
]);
也可以使用 withQueryParameters 方法:
Http::retry(3, 100)->withQueryParameters([
'name' => 'Taylor',
'page' => 1,
])->get('http://example.com/users');
发送表单 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', ['Content-Type' => 'image/jpeg']
)->post('http://example.com/attachments');
除了传入文件的原始内容,你也可以传入流资源:
$photo = fopen('photo.jpg', 'r');
$response = Http::attach(
'attachment', $photo, 'photo.jpg'
)->post('http://example.com/attachments');
请求头
使用 withHeaders 方法可以为请求添加请求头。该方法接受键值对数组:
$response = Http::withHeaders([
'X-First' => 'foo',
'X-Second' => 'bar'
])->post('http://example.com/users', [
'name' => 'Taylor',
]);
你可以使用 accept 方法,指定应用期望从请求响应中收到的内容类型:
$response = Http::accept('application/json')->get('http://example.com/users');
为方便起见,可以使用 acceptJson 方法,快速指定应用期望响应使用 application/json 内容类型:
$response = Http::acceptJson()->get('http://example.com/users');
withHeaders 会把新请求头合并到请求已有的请求头中。如有需要,可以使用 replaceHeaders 完全替换所有请求头:
$response = Http::withHeaders([
'X-Original' => 'foo',
])->replaceHeaders([
'X-Replacement' => 'bar',
])->post('http://example.com/users', [
'name' => 'Taylor',
]);
身份验证
你可以分别使用 withBasicAuth 和 withDigestAuth 方法指定 Basic 和 Digest 身份验证的凭据:
// Basic authentication...
$response = Http::withBasicAuth('[email protected] ', 'secret')->post(/* ... */);
// Digest authentication...
$response = Http::withDigestAuth('[email protected] ', 'secret')->post(/* ... */);
Bearer 令牌
如果希望快速把 Bearer 令牌添加到请求的 Authorization 头中,可以使用 withToken 方法:
$response = Http::withToken('token')->post(/* ... */);
超时
timeout 方法用于指定等待响应的最长秒数。默认情况下,HTTP 客户端会在 30 秒后超时:
$response = Http::timeout(3)->get(/* ... */);
超过指定的超时时间后,会抛出 Illuminate\Http\Client\ConnectionException 实例。
使用 connectTimeout 方法,可以指定尝试连接服务器时的最长等待秒数,默认值为 10 秒:
$response = Http::connectTimeout(3)->get(/* ... */);
重试
如果希望 HTTP 客户端在发生客户端或服务器错误时自动重试请求,可以使用 retry 方法。它接受请求的最大尝试次数,以及 Laravel 在两次尝试之间应等待的毫秒数:
$response = Http::retry(3, 100)->post(/* ... */);
如果希望自行计算每次尝试之间的等待毫秒数,可以把闭包作为 retry 方法的第二个参数:
use Exception;
$response = Http::retry(3, function (int $attempt, Exception $exception) {
return $attempt * 100;
})->post(/* ... */);
为方便起见,你也可以把数组作为 retry 的第一个参数。这个数组用于确定后续各次尝试之间应等待的毫秒数:
$response = Http::retry([100, 200])->post(/* ... */);
如有需要,可以向 retry 传入第三个参数。该参数应为可调用对象,用于判断是否实际进行重试。例如,你可能只希望在初次请求遇到 ConnectionException 时重试:
use Illuminate\Http\Client\PendingRequest;
use Throwable;
$response = Http::retry(3, 100, function (Throwable $exception, PendingRequest $request) {
return $exception instanceof ConnectionException;
})->post(/* ... */);
请求尝试失败后,你可能希望在再次尝试前修改请求。为此,可以修改传递给 retry 回调的请求参数。例如,如果第一次尝试返回身份验证错误,可以改用新的授权令牌重试:
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;
use Throwable;
$response = Http::withToken($this->getToken())->retry(2, 0, function (Throwable $exception, PendingRequest $request) {
if (! $exception instanceof RequestException || $exception->response->status() !== 401) {
return false;
}
$request->withToken($this->getNewToken());
return true;
})->post(/* ... */);
如果所有请求均失败,会抛出 Illuminate\Http\Client\RequestException 实例。如果希望禁用此行为,可以传入值为 false 的 throw 参数。禁用后,在完成所有重试尝试时,会返回客户端最后收到的响应:
$response = Http::retry(3, 100, throw: false)->post(/* ... */);
如果所有请求都因连接问题而失败,即使 throw 参数为 false,仍然会抛出 Illuminate\Http\Client\ConnectionException。
错误处理
与 Guzzle 的默认行为不同,Laravel 的 HTTP 客户端封装不会因客户端或服务器错误,即服务器返回 400 或 500 级别响应,而抛出异常。你可以使用 successful、clientError 或 serverError 方法判断是否返回了这些错误:
// 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();
// Immediately execute the given callback if there was a client or server error...
$response->onError(callable $callback);
抛出异常
如果已经有响应实例,并希望在状态码表明发生客户端或服务器错误时抛出 Illuminate\Http\Client\RequestException,可以使用 throw 或 throwIf 方法:
use Illuminate\Http\Client\Response;
$response = Http::post(/* ... */);
// Throw an exception if a client or server error occurred...
$response->throw();
// Throw an exception if an error occurred and the given condition is true...
$response->throwIf($condition);
// Throw an exception if an error occurred and the given closure resolves to true...
$response->throwIf(fn (Response $response) => true);
// Throw an exception if an error occurred and the given condition is false...
$response->throwUnless($condition);
// Throw an exception if an error occurred and the given closure resolves to false...
$response->throwUnless(fn (Response $response) => false);
// Throw an exception if the response has a specific status code...
$response->throwIfStatus(403);
// Throw an exception unless the response has a specific status code...
$response->throwUnlessStatus(200);
// Throw an exception if a server error occurred (status >= 500)...
$response->throwIfServerError();
// Throw an exception if a client error occurred (status >= 400 and < 500)...
$response->throwIfClientError();
return $response['user']['id'];
Illuminate\Http\Client\RequestException 实例有一个公开的 $response 属性,可用于检查返回的响应。
未发生错误时,throw 方法会返回响应实例,因此你可以在 throw 后继续链式调用其他操作:
return Http::post(/* ... */)->throw()->json();
如果希望在抛出异常前执行额外逻辑,可以向 throw 方法传入闭包。调用闭包后会自动抛出异常,因此无需在闭包中再次抛出:
use Illuminate\Http\Client\Response;
use Illuminate\Http\Client\RequestException;
return Http::post(/* ... */)->throw(function (Response $response, RequestException $e) {
// ...
})->json();
默认情况下,记录日志或报告异常时,RequestException 消息会截断到 120 个字符。要自定义或禁用这一行为,可以在 bootstrap/app.php 文件中配置应用所注册的行为时使用 truncateAt 和 dontTruncate 方法:
use Illuminate\Http\Client\RequestException;
->registered(function (): void {
// Truncate request exception messages to 240 characters...
RequestException::truncateAt(240);
// Disable request exception message truncation...
RequestException::dontTruncate();
})
也可以使用 truncateExceptionsAt 方法,为单个请求自定义异常截断行为:
return Http::truncateExceptionsAt(240)->post(/* ... */);
Guzzle 中间件
Laravel 的 HTTP 客户端由 Guzzle 驱动,因此可以使用 Guzzle 中间件修改发出的请求,或检查收到的响应。要修改发出的请求,可以通过 withRequestMiddleware 方法注册 Guzzle 中间件:
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\RequestInterface;
$response = Http::withRequestMiddleware(
function (RequestInterface $request) {
return $request->withHeader('X-Example', 'Value');
}
)->get('http://example.com');
同样,你也可以通过 withResponseMiddleware 方法注册中间件,检查收到的 HTTP 响应:
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\ResponseInterface;
$response = Http::withResponseMiddleware(
function (ResponseInterface $response) {
$header = $response->getHeader('X-Example');
// ...
return $response;
}
)->get('http://example.com');
全局中间件
有时你希望注册适用于每个发出请求及收到响应的中间件。这时可以使用 globalRequestMiddleware 和 globalResponseMiddleware 方法。通常应在应用的 AppServiceProvider 的 boot 方法中调用它们:
use Illuminate\Support\Facades\Http;
Http::globalRequestMiddleware(fn ($request) => $request->withHeader(
'User-Agent', 'Example Application/1.0'
));
Http::globalResponseMiddleware(fn ($response) => $response->withHeader(
'X-Finished-At', now()->toDateTimeString()
));
Guzzle 选项
使用 withOptions 方法,可以为发出的请求指定额外的 Guzzle 请求选项。该方法接受键值对数组:
$response = Http::withOptions([
'debug' => true,
])->get('http://example.com/users');
全局选项
要为每个发出的请求配置默认选项,可以使用 globalOptions 方法。通常应在应用的 AppServiceProvider 的 boot 方法中调用:
use Illuminate\Support\Facades\Http;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Http::globalOptions([
'allow_redirects' => false,
]);
}
并发请求
有时你希望并发发出多个 HTTP 请求,也就是同时派发几个请求,而不是依次发送。与较慢的 HTTP API 交互时,这可以显著改善性能。
请求池
使用 pool 方法即可实现。该方法接受一个闭包,闭包接收 Illuminate\Http\Client\Pool 实例,让你能够方便地把请求添加到池中并派发:
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;
$responses = Http::pool(fn (Pool $pool) => [
$pool->get('http://localhost/first'),
$pool->get('http://localhost/second'),
$pool->get('http://localhost/third'),
]);
return $responses[0]->ok() &&
$responses[1]->ok() &&
$responses[2]->ok();
如你所见,可以根据响应对应的请求加入池中的顺序访问各个响应实例。如果愿意,也可以使用 as 方法为请求命名,进而按名称访问相应的响应:
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;
$responses = Http::pool(fn (Pool $pool) => [
$pool->as('first')->get('http://localhost/first'),
$pool->as('second')->get('http://localhost/second'),
$pool->as('third')->get('http://localhost/third'),
]);
return $responses['first']->ok();
向 pool 方法传入 concurrency 参数,可以控制请求池的最大并发数。该值决定处理请求池时,最多可以有多少个 HTTP 请求同时处于进行状态:
$responses = Http::pool(fn (Pool $pool) => [
// ...
], concurrency: 5);
如果池中的请求在连接层面失败,例如超时或 DNS 解析失败,$responses 数组中的对应项会是 Illuminate\Http\Client\ConnectionException 实例,而不是 Response 实例:
foreach ($responses as $response) {
if ($response instanceof Throwable) {
// The request failed to connect...
} elseif ($response->failed()) {
// The request connected but received an error response...
}
}
自定义并发请求
pool 方法不能与 withHeaders、middleware 等其他 HTTP 客户端方法链式调用。如果希望为池中的请求应用自定义请求头或中间件,应在池中逐个请求上配置这些选项:
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;
$headers = [
'X-Example' => 'example',
];
$responses = Http::pool(fn (Pool $pool) => [
$pool->withHeaders($headers)->get('http://laravel.test/test'),
$pool->withHeaders($headers)->get('http://laravel.test/test'),
$pool->withHeaders($headers)->get('http://laravel.test/test'),
]);
请求批次
在 Laravel 中处理并发请求的另一种方式是使用 batch 方法。与 pool 类似,它接受一个接收 Illuminate\Http\Client\Batch 实例的闭包,让你方便地添加待派发请求;同时,它还允许定义完成回调:
use Illuminate\Http\Client\Batch;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
$responses = Http::batch(fn (Batch $batch) => [
$batch->get('http://localhost/first'),
$batch->get('http://localhost/second'),
$batch->get('http://localhost/third'),
])->before(function (Batch $batch) {
// The batch has been created but no requests have been initialized...
})->progress(function (Batch $batch, int|string $key, Response $response) {
// An individual request has completed successfully...
})->then(function (Batch $batch, array $results) {
// All requests completed successfully...
})->catch(function (Batch $batch, int|string $key, Response|RequestException|ConnectionException $response) {
// Batch request failure detected...
})->finally(function (Batch $batch, array $results) {
// The batch has finished executing...
})->send();
与 pool 方法一样,可以使用 as 方法为请求命名:
$responses = Http::batch(fn (Batch $batch) => [
$batch->as('first')->get('http://localhost/first'),
$batch->as('second')->get('http://localhost/second'),
$batch->as('third')->get('http://localhost/third'),
])->send();
调用 send 方法启动 batch 后,不能再向其中添加新请求。尝试这样做会抛出 Illuminate\Http\Client\BatchInProgressException。
可以通过 concurrency 方法控制请求批次的最大并发数。该值决定处理批次时,最多可以有多少个 HTTP 请求同时处于进行状态:
$responses = Http::batch(fn (Batch $batch) => [
// ...
])->concurrency(5)->send();
检查批次
传递给批次完成回调的 Illuminate\Http\Client\Batch 实例提供了多种属性和方法,帮助你与指定批次交互并检查其状态:
// The number of requests assigned to the batch...
$batch->totalRequests;
// The number of requests that have not been processed yet...
$batch->pendingRequests;
// The number of requests that have failed...
$batch->failedRequests;
// The number of requests that have been processed thus far...
$batch->processedRequests();
// Indicates if the batch has finished executing...
$batch->finished();
// Indicates if the batch has request failures...
$batch->hasFailures();
延后执行批次
调用 defer 方法时,不会立即执行请求批次。Laravel 会在当前应用请求的 HTTP 响应发送给用户之后,再执行该批次,使应用保持快速响应:
use Illuminate\Http\Client\Batch;
use Illuminate\Support\Facades\Http;
$responses = Http::batch(fn (Batch $batch) => [
$batch->get('http://localhost/first'),
$batch->get('http://localhost/second'),
$batch->get('http://localhost/third'),
])->then(function (Batch $batch, array $results) {
// All requests completed successfully...
})->defer();
宏
Laravel HTTP 客户端允许定义“宏”。当应用中多处需要与服务交互时,宏提供了一种流畅、清晰的方式,用于配置通用的请求路径和请求头。首先,可以在应用的 App\Providers\AppServiceProvider 类的 boot 方法中定义宏:
use Illuminate\Support\Facades\Http;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Http::macro('github', function () {
return Http::withHeaders([
'X-Example' => 'example',
])->baseUrl('https://github.com');
});
}
宏配置好后,你可以在应用的任何位置调用它,创建具有指定配置的待发送请求:
$response = Http::github()->get('/');
测试
Laravel 的许多服务都提供功能,让你轻松、清晰地编写测试,HTTP 客户端也不例外。Http 门面的 fake 方法可以指示客户端,在发起请求时返回桩响应或模拟响应。
模拟响应
例如,要让 HTTP 客户端为每个请求返回状态码为 200 的空响应,可以无参数调用 fake:
use Illuminate\Support\Facades\Http;
Http::fake();
$response = Http::post(/* ... */);
模拟特定 URL
也可以向 fake 方法传入数组。数组的键表示希望模拟的 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 模式,为所有未匹配的 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']),
]);
为方便起见,可以分别提供字符串、数组或整数作为响应,生成简单字符串响应、JSON 响应或空响应:
Http::fake([
'google.com/*' => 'Hello World',
'github.com/*' => ['foo' => 'bar'],
'chatgpt.com/*' => 200,
]);
模拟异常
有时你需要测试:HTTP 客户端尝试发出请求时遇到 Illuminate\Http\Client\ConnectionException,应用会如何表现。使用 failedConnection 方法,可以让客户端抛出连接异常:
Http::fake([
'github.com/*' => Http::failedConnection(),
]);
要测试抛出 Illuminate\Http\Client\RequestException 时应用的行为,可以使用 failedRequest 方法:
$this->mock(GithubService::class)
->shouldReceive('getUser')
->andThrow(
Http::failedRequest(['code' => 'not_found'], 404)
);
模拟响应序列
有时你需要让某个 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 方法传入闭包。闭包接收 Illuminate\Http\Client\Request 实例,并应返回响应实例。在闭包内,你可以执行决定返回何种响应所需的任何逻辑:
use Illuminate\Http\Client\Request;
Http::fake(function (Request $request) {
return Http::response('Hello World', 200);
});
检查请求
模拟响应时,你可能需要检查客户端收到的请求,确保应用发送了正确的数据或请求头。为此,可以在调用 Http::fake 后调用 Http::assertSent。
assertSent 接受一个闭包,闭包接收 Illuminate\Http\Client\Request 实例,并返回一个布尔值,表示请求是否符合预期。至少必须发出一个符合给定预期的请求,测试才会通过:
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\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 Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\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';
});
可以使用 assertSentCount 方法,断言测试中“发送”了多少个请求:
Http::fake();
Http::assertSentCount(5);
也可以使用 assertNothingSent 方法,断言测试期间没有发出请求:
Http::fake();
Http::assertNothingSent();
记录请求和响应
使用 recorded 方法,可以收集所有请求及其对应响应。该方法返回由数组组成的集合,数组中包含 Illuminate\Http\Client\Request 和 Illuminate\Http\Client\Response 实例:
Http::fake([
'https://laravel.com' => Http::response(status: 500),
'https://nova.laravel.com/' => Http::response(),
]);
Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');
$recorded = Http::recorded();
[$request, $response] = $recorded[0];
此外,recorded 方法接受一个闭包,闭包接收 Illuminate\Http\Client\Request 和 Illuminate\Http\Client\Response 实例。你可以根据预期,用它筛选请求与响应对:
use Illuminate\Http\Client\Request;
use Illuminate\Http\Client\Response;
Http::fake([
'https://laravel.com' => Http::response(status: 500),
'https://nova.laravel.com/' => Http::response(),
]);
Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');
$recorded = Http::recorded(function (Request $request, Response $response) {
return $request->url() !== 'https://laravel.com' &&
$response->successful();
});
防止未模拟请求
如果希望确保单个测试或整个测试套件中,通过 HTTP 客户端发出的所有请求都已被模拟,可以调用 preventStrayRequests。调用后,任何没有对应模拟响应的请求都会抛出异常,而不会发出真实 HTTP 请求:
use Illuminate\Support\Facades\Http;
Http::preventStrayRequests();
Http::fake([
'github.com/*' => Http::response('ok'),
]);
// An "ok" response is returned...
Http::get('https://github.com/laravel/framework');
// An exception is thrown...
Http::get('https://laravel.com');
有时你希望阻止大部分未模拟请求,同时仍允许特定请求实际执行。这时可以向 allowStrayRequests 方法传入 URL 模式数组。匹配其中任一模式的请求都会被允许,其他请求则仍然会抛出异常:
use Illuminate\Support\Facades\Http;
Http::preventStrayRequests();
Http::allowStrayRequests([
'http://127.0.0.1:5000/*',
]);
// This request is executed...
Http::get('http://127.0.0.1:5000/generate');
// An exception is thrown...
Http::get('https://laravel.com');
事件
Laravel 在发送 HTTP 请求的过程中触发三个事件。RequestSending 在请求发送前触发;ResponseReceived 在收到指定请求的响应后触发;如果指定请求没有收到响应,则触发 ConnectionFailed。
RequestSending 和 ConnectionFailed 都包含公开的 $request 属性,可用于检查 Illuminate\Http\Client\Request 实例。ResponseReceived 同样包含 $request,并额外包含 $response 属性,可用于检查 Illuminate\Http\Client\Response 实例。你可以在应用中为这些事件创建事件监听器:
use Illuminate\Http\Client\Events\RequestSending;
class LogRequest
{
/**
* Handle the event.
*/
public function handle(RequestSending $event): void
{
// $event->request ...
}
}
本文译自 Laravel 官方文档 HTTP Client,当前页面标识为 Laravel 13.x。原作者为 Taylor Otwell 及 Laravel 文档贡献者。文档仓库的 13.x 许可文件采用 MIT 许可,版权所有 © Taylor Otwell。本版翻译说明文字并调整排版,保留全部示例代码;示例中经网页保护的邮件地址保留原页面显示形式。以下保留完整许可声明。
MIT 许可声明
The MIT License (MIT)
Copyright (c) Taylor Otwell
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.











暂无评论内容