在laravel框架中的5个HTTP客户端技巧分享

2023-06-01 00:00:00 客户端 框架 技巧

作为网络开发者, 我们经常需要与Laravel应用程序的API进行交互. Laravel HTTP客户端,在第7版中引入,为Guzzle HTTP库提供了一个方便和直观的包装。

在这篇文章中, 我们将探讨五个有价值的技巧来使用Laravel HTTP客户端, 这些技巧可以使你的开发经验更加高效和愉快.


这些技巧包括使用HTTP宏,为容器服务配置HTTP客户端,可移植的基本URL配置,防止测试中的杂散请求,以及监听HTTP事件。

通过掌握这些技巧, 你可以简化你的API交互, 并创建更强大和可维护的Laravel应用程序.


HTTP宏

许多Laravel的服务有一个 "宏 "的功能,允许你为你的应用程序定义自定义方法。

而不是从Laravel框架中扩展核心类,你可以将这些宏添加到服务提供者的boot()方法中。


HTTP文档显示了一个宏的例子

https://laravel.com/docs/10.x/http-client#macros

你可以用它来定义常见的设置:

public function boot(): void
{
    Http::macro('github', function () {
        return Http::withHeaders([
            'X-Example' => 'example',
        ])->baseUrl('https://github.com');
    });
}
 
// Usage
response = Http::github()->get('/');

宏可以定义任何你想在你的应用程序中定义和重用的方便方法。

文档中的宏的例子触及了配置HTTP客户端以用于其他服务的另一个提示。

我们将在下一节重新审视将宏与传递给其他容器服务的客户端相结合。


为容器服务配置HTTP客户端

当从Laravel应用中与API交互时, 你很可能需要对客户端进行各种可配置的设置. 

例如, 如果API有多个环境, 你会想要一个可配置的基本URL, 令牌, 超时设置, 以及更多.


我们可以利用宏来定义客户端,将客户端表示为自己的服务,也可以注入其他服务,或者两者都有。

首先,让我们看看在服务提供者的register()方法中定义客户端设置:

public function register(): void
{
    $this->app->singleton(ExampleService::class, function (Application $app) {
        $client = Http::withOptions([
            'base_uri' => config('services.example.base_url'),
            'timeout' => config('services.example.timeout', 10),
            'connect_timeout' => config('services.example.connect_timeout', 2),
        ])->withToken(config('services.example.token'));
 
        return new ExampleService($client);
    });
}

在单子服务定义中,我们用链子连接了几个调用来配置客户端。

其结果是一个PendingRequest实例,我们可以将其传递给我们的服务构造函数,

如下所示:

class ExampleService
{
    public function __construct(
        private PendingRequest $client
    ) {}
 
    public function getWidget(string $uid)
    {
        $response = $this->client
            ->withUrlParameters(['uid' => $uid])
            ->get('widget/{uid}');
 
        return new Widget($response->json());
    }
}

这个服务使用withOptions()方法来直接配置Guzzle的选项,

但我们也可以使用HTTP客户端提供的一些便利方法:

$this->app->singleton(ExampleService::class, function (Application $app) {
    $client = Http::baseUrl(config('services.example.base_url'))
        ->timeout(config('services.example.timeout', 10))
        ->connectTimeout(config('services.example.connect_timeout', 2))
        ->withToken(config('services.example.token'));
 
    return new ExampleService($client);
});


或者,如果你想把宏和服务结合起来,你可以使用你在AppServiceProvider的boot()方法中定义的宏:

$this->app->singleton(ExampleService::class, function (Application $app) {
    return new ExampleService(Http::github());
});

可移植的基本URL配置

你可能已经看到默认的基本URL包含了一个尾部的/,因为根据RFC 3986,它在我的选项中提供了最大的可移植性。

以下面的服务配置为例(注意默认的base_url):

return [
    'example' => [
        'base_url' => env('EXAMPLE_BASE_URI', 'https://api.example.com/v1/'),
        'token' => env('EXAMPLE_SERVICE_TOKEN'),
        'timeout' => env('EXAMPLE_SERVICE_TIMEOUT', 10),
        'connect_timeout' => env('EXAMPLE_SERVICE_TIMEOUT', 2),
    ],
];

如果我们的API在生产中和暂存中都有一个路径前缀/v1/,也许它只是https://stg-api.example.com/;

使用尾部斜线可以使URLs按预期工作,而不需要修改代码。

在配置尾部/的同时,注意我代码中所有的API调用都使用相对路径:

$this->client
    ->withUrlParameters(['uid' => $uid])
    // Example:
    // Staging - https://stg-api.example.com/widget/123
    // Production - https://api.example.com/v1/widget/123
    ->get('widget/{uid}');

请参阅Guzzle的创建客户端文档,看看不同的base_uri风格如何影响URI的解析。

https://docs.guzzlephp.org/en/stable/quickstart.html#creating-a-client


防止测试中的杂散请求

Laravel的HTTP客户端提供了优秀的测试工具,使编写测试变得轻而易举。

当我写与API交互的代码时, 我感到不安的是我的测试有实际的网络请求发生. 

用Laravel的HTTP客户端来防止杂乱的请求:

Http::preventStrayRequests();
 
Http::fake([
    'github.com/*' => Http::response('ok'),
]);
 
// Run test code
// If any other code triggers an HTTP call via Laravel's client
// an exception is thrown.

在我看来,使用preventStrayRequests()的最好方法是在你期望与 API 互动的测试类中定义一个 setUp() 方法。

也许你也可以把它添加到你的应用程序的基础TestCase类中:

namespace Tests;
 
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Http;
 
abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
 
    public function setUp(): void
    {
        parent::setUp();
 
        Http::preventStrayRequests();
    }
}

这样做将确保你的测试套件中触发的每个HTTP客户端调用都有一个假的请求支持。

使用这种方法让我信心大增,因为我的测试中所有的出站请求都有一个等价的假请求。


HTTP事件的日志处理程序

Laravel的HTTP客户端有很多有价值的事件,你可以用它们来快速进入请求/响应生命周期的重要阶段。

在写这篇文章的时候, 有三个事件被触发:

Illuminate\Http\Client\Events\RequestSending
Illuminate\Http\Client\Events\ResponseReceived
Illuminate\Http\Client\Events\ConnectionFailed

比方说,你想把你的应用程序发出请求的每个URL可视化。

我们可以很容易地接入RequestSending事件,并记录出每个请求:

namespace App\Listeners;
 
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
 
class LogRequestSending
{
    public function handle(object $event): void
    {
        Log::debug('HTTP request is being sent.', [
            'url' => $event->request->url(),
        ]);
    }
}

为了使事件处理程序工作,在EventServiceProvider类中添加以下内容。

use App\Listeners\LogRequestSending;
use Illuminate\Http\Client\Events\RequestSending;
// ...
protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
    RequestSending::class => [
        LogRequestSending::class,
    ],
];

一旦它被连接起来,你就会在你的日志中看到类似于HTTP客户端尝试的每个请求的内容:

[2023-03-17 04:06:03] local.DEBUG: HTTP request is being sent. {"url":"https://api.example.com/v1/widget/123"}


了解更多

官方的Laravel HTTP文档有你所需要的一切来开始。

https://laravel.com/docs/10.x/http-client

我希望这个教程能给你一些灵感和技巧, 你可以在你的Laravel应用程序中使用.


转:

https://laravel-news.com/laravel-http-client-tips

相关文章