Skip to content
赞助商赞助商赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

HTTP 客户端

介绍

Laravel 提供了一个围绕 Guzzle HTTP 客户端的简洁、最小化的 API,使您能够快速发起外部 HTTP 请求以与其他 Web 应用程序通信。Laravel 对 Guzzle 的封装专注于其最常见的用例和出色的开发者体验。

在开始之前,您应该确保已将 Guzzle 包作为应用程序的依赖项安装。默认情况下,Laravel 自动包含此依赖项:

php
composer require guzzlehttp/guzzle

发起请求

要发起请求,您可以使用 getpostputpatchdelete 方法。首先,让我们看看如何发起一个基本的 GET 请求:

php
use Illuminate\Support\Facades\Http;

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

get 方法返回一个 Illuminate\Http\Client\Response 实例,该实例提供了多种方法可用于检查响应:

php
$response->body() : string;
$response->json() : array|mixed;
$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;

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

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

请求数据

当然,在使用 POSTPUTPATCH 时,通常会发送附加数据。因此,这些方法接受一个数组作为第二个参数。默认情况下,数据将使用 application/json 内容类型发送:

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

GET 请求查询参数

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

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

发送表单 URL 编码请求

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

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

发送原始请求体

如果您希望在发起请求时提供原始请求体,可以使用 withBody 方法:

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

多部分请求

如果您希望以多部分请求发送文件,您应该在发起请求之前调用 attach 方法。此方法接受文件的名称及其内容。可选地,您可以提供第三个参数作为文件的文件名:

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

除了传递文件的原始内容,您还可以传递流资源:

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

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

请求头

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

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

认证

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

php
// 基本认证...
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(...);

// 摘要认证...
$response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(...);

Bearer 令牌

如果您希望快速向请求添加 Authorization bearer 令牌头,可以使用 withToken 方法:

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

超时

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

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

如果超出给定的超时时间,将抛出 Illuminate\Http\Client\ConnectionException 实例。

重试

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

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

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

错误处理

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

php
// 确定状态码是否 >= 200 且 < 300...
$response->successful();

// 确定状态码是否 >= 400...
$response->failed();

// 确定响应是否具有 400 级别状态码...
$response->clientError();

// 确定响应是否具有 500 级别状态码...
$response->serverError();

抛出异常

如果您有一个响应实例,并希望在响应为客户端或服务器错误时抛出 Illuminate\Http\Client\RequestException 实例,可以使用 throw 方法:

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

// 如果发生客户端或服务器错误,则抛出异常...
$response->throw();

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

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

如果没有发生错误,throw 方法将返回响应实例,允许您在 throw 方法上链接其他操作:

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

Guzzle 选项

您可以使用 withOptions 方法指定其他 Guzzle 请求选项withOptions 方法接受一个键/值对数组:

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

测试

许多 Laravel 服务提供功能,帮助您轻松且富有表现力地编写测试,Laravel 的 HTTP 封装也不例外。Http facade 的 fake 方法允许您指示 HTTP 客户端在发起请求时返回模拟/虚拟响应。

伪造响应

例如,要指示 HTTP 客户端为每个请求返回空的、200 状态码的响应,您可以在不传递参数的情况下调用 fake 方法:

php
use Illuminate\Support\Facades\Http;

Http::fake();

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

伪造特定 URL

或者,您可以将数组传递给 fake 方法。数组的键应表示您希望伪造的 URL 模式及其关联的响应。* 字符可以用作通配符。对未伪造的 URL 发起的任何请求将实际执行。您可以使用 response 方法为这些端点构建模拟/虚拟响应:

php
Http::fake([
    // 为 GitHub 端点模拟 JSON 响应...
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // 为 Google 端点模拟字符串响应...
    'google.com/*' => Http::response('Hello World', 200, ['Headers']),
]);

如果您希望指定一个回退 URL 模式以模拟所有未匹配的 URL,可以使用单个 * 字符:

php
Http::fake([
    // 为 GitHub 端点模拟 JSON 响应...
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // 为所有其他端点模拟字符串响应...
    '*' => Http::response('Hello World', 200, ['Headers']),
]);

伪造响应序列

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

php
Http::fake([
    // 为 GitHub 端点模拟一系列响应...
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->pushStatus(404),
]);

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

php
Http::fake([
    // 为 GitHub 端点模拟一系列响应...
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->whenEmpty(Http::response()),
]);

如果您希望伪造一系列响应但不需要指定应伪造的特定 URL 模式,可以使用 Http::fakeSequence 方法:

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

伪造回调

如果您需要更复杂的逻辑来确定某些端点应返回的响应,可以将回调传递给 fake 方法。此回调将接收一个 Illuminate\Http\Client\Request 实例,并应返回一个响应实例:

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

检查请求

在伪造响应时,您可能偶尔希望检查客户端接收到的请求,以确保您的应用程序发送了正确的数据或请求头。您可以通过在调用 Http::fake 后调用 Http::assertSent 方法来实现此目的。

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

php
Http::fake();

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

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

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

php
Http::fake();

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

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

或者,如果您希望断言未发送任何请求,可以使用 assertNothingSent 方法:

php
Http::fake();

Http::assertNothingSent();