Giới thiệu

Laravel cung cấp một API nhỏ, rõ ràng dựa trên thư viện Guzzle HTTP client, cho phép bạn nhanh chóng thực hiện các HTTP request giao tiếp với các ứng dụng web khác. API này tập trung vào các trường hợp sử dụng phổ biến và giúp tăng trải nghiệm tuyệt vời dành cho nhà phát triển.

Trước khi bắt đầu, bạn nên đảm bảo là bạn đã cài đặt package Guzzle vào trong ứng dụng của bạn. Mặc định, Laravel đã chứa thư viện này. Tuy nhiên, nếu trước đó bạn đã gỡ package này ra rồi, thì bạn có thể cài đặt lại package này qua Composer:

composer require guzzlehttp/guzzle

Tạo Request

Để tạo request, bạn có thể sử dụng các phương thức head, get, post, put, patch, và delete được cung cấp bởi facade Http. Đầu tiên, hãy xem cách tạo ra một request GET cơ bản to another URL:

use Illuminate\Support\Facades\Http;

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

Phương thức get sẽ trả về một instance của Illuminate\Http\Client\Response và cung cấp nhiều phương thức có thể được sử dụng để kiểm tra response:

$response->body() : string;
$response->json($key = null) : array|mixed;
$response->object() : object;
$response->collect($key = null) : Illuminate\Support\Collection;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->redirect(): bool;
$response->failed() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;

Đối tượng Illuminate\Http\Client\Response cũng được implement từ interface ArrayAccess của PHP, cho phép bạn truy cập trực tiếp vào dữ liệu JSON trong response:

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

Dumping Requests

Nếu bạn muốn dump ra instance request trước khi nó được gửi đi và dừng quá trình chạy lại, bạn có thể thêm phương thức dd vào đầu định nghĩa request của bạn:

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

Request Data

Tất nhiên, thông thường khi tạo request POST, PUTPATCH bạn sẽ cần gửi thêm dữ liệu vào request của bạn, vì thế, các phương thức này sẽ chấp nhận thêm một mảng dữ liệu làm tham số thứ hai của chúng. Mặc định, dữ liệu sẽ được gửi theo kiểu application/json:

use Illuminate\Support\Facades\Http;

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

GET Request Query Parameters

Khi thực hiện các request GET, bạn có thể muốn nối một chuỗi query vào sau URL hoặc truyền một mảng gồm các cặp khóa và giá trị làm tham số thứ hai cho phương thức get:

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

Sending Form URL Encoded Requests

Nếu bạn muốn gửi dữ liệu theo kiểu application/x-www-form-urlencoded, bạn nên gọi phương thức asForm trước khi tạo request của bạn:

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

Sending A Raw Request Body

Bạn có thể sử dụng phương thức withBody nếu bạn muốn đưa vào một nội dung request thô khi tạo request. Content type cũng có thể được cung cấp thông qua tham số thứ hai của phương thức:

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

Multi-Part Requests

Nếu bạn muốn gửi một file dưới dạng request multi-part, bạn nên gọi phương thức attach trước khi tạo request của bạn. Phương thức này chấp nhận tên của file và nội dung của file đó. Nếu cần, bạn cũng có thể cung cấp thêm tham số thứ ba sẽ được coi là filename của file:

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

Thay vì truyền nội dung thô của một file, bạn có thể truyền một stream resource:

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

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

Headers

Header có thể được thêm vào các request bằng phương thức withHeaders. Phương thức withHeaders này chấp nhận một mảng các cặp khóa và giá trị:

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

Bạn có thể sử dụng phương thức accept để chỉ định content type nào mà ứng dụng của bạn mong đợi để đáp ứng yêu cầu của bạn:

$response = Http::accept('application/json')->get('http://example.com/users');

Để thuận tiện, bạn có thể sử dụng phương thức acceptJson để nhanh chóng xác định rằng ứng dụng của bạn mong đợi content type application/json sẽ đáp ứng yêu cầu của bạn:

$response = Http::acceptJson()->get('http://example.com/users');

Authentication

Bạn có thể chỉ định thông tin xác thực là basic authentication hay digest authentication bằng cách sử dụng các phương thức withBasicAuthwithDigestAuth:

// Basic authentication...
$response = Http::withBasicAuth('[email protected]', 'secret')->post(...);

// Digest authentication...
$response = Http::withDigestAuth('[email protected]', 'secret')->post(...);

Bearer Tokens

Nếu bạn muốn thêm nhanh header Authorization bearer token vào trong header Authorization của request, bạn có thể sử dụng phương thức withToken:

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

Timeout

Phương thức timeout có thể được sử dụng để chỉ định số giây tối đa có thể chờ một response:

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

Nếu thời gian chờ bị vượt quá, một instance của Illuminate\Http\Client\ConnectionException sẽ được đưa ra.

Retries

Nếu bạn muốn HTTP client tự động thử lại request nếu xảy ra lỗi ở phía client hoặc ở phía server, bạn có thể sử dụng phương thức retry. Phương thức retry sẽ chấp nhận hai tham số: một là số lần request tối đa có thể được thử lại và hai là số mili giây mà Laravel sẽ đợi giữa các lần thử:

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

Nếu cần, bạn có thể truyền tham số thứ ba cho phương thức retry. Tham số thứ ba phải là một tham số callable để xác định xem có thực sự nên thử lại hay không. Ví dụ: bạn có thể chỉ muốn thử lại request nếu request ban đầu gặp phải lỗi ConnectionException:

$response = Http::retry(3, 100, function ($exception) {
    return $exception instanceof ConnectionException;
})->post(...);

Nếu tất cả các request đều thất bại, thì một instance của Illuminate\Http\Client\RequestException sẽ được đưa ra.

Xử lý lỗi

Không giống như hành vi mặc định của thư viện Guzzle, HTTP client wrapper của Laravel sẽ không đưa ra các ngoại lệ đối với các lỗi client hoặc server (như response 400500 từ server). Bạn có thể xác định xem một trong những lỗi này có được trả về hay không bằng cách sử dụng các phương thức successful, clientError, hoặc 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);

Throwing Exceptions

Nếu bạn có một instance response và muốn đưa ra một instance Illuminate\Http\Client\RequestException nếu response status code trả về là một lỗi của client hoặc là của server, bạn có thể sử dụng phương thức throw hoặc throwIf:

$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);

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

Instance Illuminate\Http\Client\RequestException có một thuộc tính public là $response sẽ cho phép bạn kiểm tra response được trả về.

Phương thức throw sẽ trả về một instance response nếu như không có lỗi xảy ra, cho phép bạn kết hợp các thao tác khác nhau vào phương thức throw:

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

Nếu bạn muốn thực hiện một số logic bổ sung trước khi đưa ra exception, bạn có thể truyền một closure cho phương thức throw. Exception này sẽ được đưa ra tự động sau khi closure được gọi, do đó bạn không cần phải đưa lại exception này từ bên trong closure:

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

Guzzle Options

Bạn có thể chỉ định thêm các tuỳ chọn Guzzle request bằng cách sử dụng phương thức withOptions. Phương thức withOptions sẽ chấp nhận một mảng gồm các cặp khóa và giá trị:

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

Request đồng thời

Thỉnh thoảng, bạn có thể muốn thực hiện nhiều request HTTP cùng một lúc. Nói cách khác, bạn muốn một số request được gửi đi cùng lúc thay vì gửi đi các request một cách tuần tự. Điều này có thể giúp cải thiện hiệu suất đáng kể khi tương tác với các API HTTP chậm.

Rất may, bạn có thể thực hiện việc này bằng phương thức pool. Phương thức pool chấp nhận một closure nhận instance Illuminate\Http\Client\Pool, cho phép bạn dễ dàng thêm request vào một nhóm request để gửi đi:

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();

Như bạn có thể thấy, mỗi instance response có thể được truy cập dựa trên thứ tự của nó được thêm vào nhóm. Nếu muốn, bạn có thể đặt tên cho các request của bạn bằng phương thức as, phương thức này cho phép bạn truy cập các response tương ứng theo tên:

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();

Macros

Laravel HTTP client cho phép bạn định nghĩa "macro", cái mà có thể hoạt động như một cơ chế hiệu quả tuyệt vời để cấu hình các path và các header cho một request chung khi nó tương tác với các service trong ứng dụng của bạn. Để bắt đầu, bạn có thể định nghĩa một macro trong phương thức boot của class App\Providers\AppServiceProvider trong ứng dụng của bạn:

use Illuminate\Support\Facades\Http;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Http::macro('github', function () {
        return Http::withHeaders([
            'X-Example' => 'example',
        ])->baseUrl('https://github.com');
    });
}

Khi macro của bạn đã được cấu hình xong, bạn có thể gọi nó từ bất kỳ đâu trong ứng dụng của bạn để tạo ra một pending request với cấu hình đã chỉ định:

$response = Http::github()->get('/');

Testing

Nhiều service của Laravel cung cấp các chức năng giúp bạn viết các bài test một cách dễ dàng và rõ ràng, và HTTP client wrapper của Laravel cũng không phải là một ngoại lệ. Phương thức fake của facade Http cho phép bạn hướng dẫn HTTP client trả về một response stubbed / dummy khi một request được tạo.

Faking Responses

Ví dụ: để hướng dẫn HTTP client trả về một response trống và có status code 200 cho mọi request, bạn có thể gọi phương thức fake với không tham số truyền vào:

use Illuminate\Support\Facades\Http;

Http::fake();

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

{note} Khi fake một request, HTTP client middleware sẽ không được chạy. Bạn nên định nghĩa các kỳ vọng của bạn đối với các fake request như thể là các middleware này đã được chạy chính xác.

Faking Specific URLs

Ngoài ra, bạn cũng có thể truyền một mảng cho phương thức fake. Các khóa của mảng phải đại diện cho các pattern URL mà bạn muốn làm fake còn các giá trị là các response tương ứng với chúng. Ký tự * có thể được sử dụng làm ký tự đại diện. Bất kỳ request nào được tạo với một URL không bị fake sẽ được thực thi ngay lập tức. Bạn có thể sử dụng phương thức response của facade Http để tạo các response stub / fake cho các endpoint này:

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),
]);

Nếu bạn muốn chỉ định một pattern URL dự phòng sẽ được dùng cho tất cả các URL mà chưa khớp với các pattern URL đã cho, bạn có thể sử dụng một ký tự * để cài đặt chuyện đó:

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']),
]);

Faking Response Sequences

Đôi khi bạn có thể cần chỉ định là một URL sẽ trả về một loạt các response fake theo một trình tự cụ thể. Bạn có thể thực hiện điều này bằng cách sử dụng phương thức Http::sequence để xây dựng các response:

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

Khi tất cả các response trong một trình tự response đã được sử dụng xong, thì bất kỳ request nào khác sẽ khiến trình tự response sẽ đưa ra một ngoại lệ. Nếu bạn muốn chỉ định một response mặc định sẽ được trả về khi một trình chạy xong, bạn có thể sử dụng phương thức 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()),
]);

Nếu bạn muốn fake một trình tự response nhưng không muốn chỉ định pattern URL nào sẽ được làm fake, bạn có thể sử dụng phương thức Http::fakeSequence:

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

Fake Callback

Nếu bạn yêu cầu một logic phức tạp hơn để xác định response nào sẽ trả về cho một số endpoint nhất định, bạn có thể truyền voà một lệnh closure cho phương thức fake. Lệnh closure này sẽ nhận vào một instance của Illuminate\Http\Client\Request và sẽ trả về một instance response. Trong closure của bạn, bạn có thể thực hiện bất kỳ logic nào cần thiết để xác định loại response nào sẽ trả về:

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

Kiểm tra Requests

Khi fake response, đôi khi bạn có thể muốn kiểm tra các request mà client nhận được để đảm bảo là ứng dụng của bạn đang gửi dữ liệu hoặc tiêu đề chính xác. Bạn có thể thực hiện điều này bằng cách gọi phương thức Http::assertSent sau khi gọi Http::fake.

Phương thức assertSent sẽ chấp nhận một closure sẽ nhận vào một instance Illuminate\Http\Client\Request và sẽ trả về một giá trị boolean cho biết là request có phù hợp với mong đợi của bạn hay không. Để pass qua bài test, thì ít nhất một request phải phù hợp với các kỳ vọng mà bạn đưa ra:

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';
});

Nếu cần thiết, bạn có thể kiểm tra rằng một request sẽ không được gửi đi bằng phương thức 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';
});

Bạn có thể sử dụng phương thức assertSentCount để kiểm tra có bao nhiêu request đã được "gửi" trong quá trình test:

Http::fake();

Http::assertSentCount(5);

Hoặc, bạn có thể sử dụng phương thức assertNothingSent để kiểm tra không có request nào được gửi đi trong quá trình test:

Http::fake();

Http::assertNothingSent();

Events

Laravel kích hoạt ba event trong quá trình gửi request HTTP. Event RequestSending sẽ được kích hoạt trước khi request được gửi đi, trong khi event ResponseReceived sẽ được kích hoạt sau khi nhận được phản hồi cho một request nhất định. Và event ConnectionFailed sẽ được kích hoạt nếu không nhận được phản hồi nào cho một request nhất định.

Cả hai event RequestSendingConnectionFailed đều chứa thuộc tính public $request mà bạn có thể sử dụng để kiểm tra instance Illuminate\Http\Client\Request. Tương tự, event ResponseReceived cũng chứa thuộc tính $request cũng như thuộc tính $response có thể được sử dụng để kiểm tra instance Illuminate\Http\Client\Response. Bạn cũng có thể đăng ký event listener cho event này trong service provider App\Providers\EventServiceProvider của bạn:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'Illuminate\Http\Client\Events\RequestSending' => [
        'App\Listeners\LogRequestSending',
    ],
    'Illuminate\Http\Client\Events\ResponseReceived' => [
        'App\Listeners\LogResponseReceived',
    ],
    'Illuminate\Http\Client\Events\ConnectionFailed' => [
        'App\Listeners\LogConnectionFailed',
    ],
];
Helpers Localization
© 2023 by Logo page doc-vn