HTTP-клієнт · Laravel
Вступ
Laravel надає виразний мінімальний API навколо HTTP-клієнта Guzzle, який дозволяє швидко виконувати вихідні HTTP-запити для взаємодії з іншими вебзастосунками. Обгортка Laravel навколо Guzzle зосереджена на найпоширеніших сценаріях використання та зручності для розробника.
Виконання запитів
Щоб виконувати запити, скористайтеся методами head, get, post, put, patch і delete, які надає фасад Http. Спершу подивімося, як виконати простий GET-запит до іншої URL-адреси:
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 Internal Server Error
Шаблони URI
HTTP-клієнт також дозволяє будувати URL-адреси запитів за специфікацією шаблонів URI. Щоб задати параметри URL, які підставлятиме ваш шаблон URI, скористайтеся методом withUrlParameters:
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');
Надсилання запитів у форматі form URL encoded
Щоб надіслати дані з типом вмісту 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');
Multi-part запити
Щоб надсилати файли як multi-part запити, викличте метод 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. Метод 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',
]);
Автентифікація
Облікові дані для basic- і digest-автентифікації задаються методами withBasicAuth і withDigestAuth відповідно:
// Basic-автентифікація...
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(/* ... */);
// Digest-автентифікація...
$response = Http::withDigestAuth('taylor@laravel.com', '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. Метод 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 можна передати третій аргумент. Третім аргументом має бути callable, який визначає, чи справді слід робити повторні спроби. Наприклад, ви можете повторювати запит лише тоді, коли початковий запит наштовхнувся на ConnectionException:
use Illuminate\Http\Client\PendingRequest;
use Throwable;
$response = Http::retry(3, 100, function (Throwable $exception, PendingRequest $request) {
return $exception instanceof ConnectionException;
})->post(/* ... */);
Якщо спроба запиту зазнала невдачі, перед новою спробою може знадобитися змінити сам запит. Це робиться через модифікацію аргументу запиту, який передається у ваш callable для методу 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. Щоб вимкнути цю поведінку, передайте аргумент throw зі значенням false. Тоді після всіх спроб буде повернуто останню відповідь, яку отримав клієнт:
$response = Http::retry(3, 100, throw: false)->post(/* ... */);
Попередження Якщо всі запити зазнають невдачі через проблему зі з'єднанням,
Illuminate\Http\Client\ConnectionExceptionбуде викинуто навіть тоді, коли аргументthrowмає значенняfalse.
Обробка помилок
На відміну від типової поведінки Guzzle, обгортка HTTP-клієнта Laravel не викидає винятків на клієнтські чи серверні помилки (відповіді серверів рівня 400 і 500). Визначити, чи повернулася така помилка, можна методами successful, clientError або serverError:
// Визначити, чи код статусу >= 200 і < 300...
$response->successful();
// Визначити, чи код статусу >= 400...
$response->failed();
// Визначити, чи відповідь має код статусу рівня 400...
$response->clientError();
// Визначити, чи відповідь має код статусу рівня 500...
$response->serverError();
// Негайно виконати заданий колбек, якщо сталася клієнтська або серверна помилка...
$response->onError(callable $callback);
Викидання винятків
Якщо у вас є екземпляр відповіді й ви хочете викинути екземпляр Illuminate\Http\Client\RequestException, коли код статусу відповіді вказує на клієнтську чи серверну помилку, скористайтеся методами throw або throwIf:
use Illuminate\Http\Client\Response;
$response = Http::post(/* ... */);
// Викинути виняток, якщо сталася клієнтська або серверна помилка...
$response->throw();
// Викинути виняток, якщо сталася помилка і задана умова істинна...
$response->throwIf($condition);
// Викинути виняток, якщо сталася помилка і задане замикання повертає true...
$response->throwIf(fn (Response $response) => true);
// Викинути виняток, якщо сталася помилка і задана умова хибна...
$response->throwUnless($condition);
// Викинути виняток, якщо сталася помилка і задане замикання повертає false...
$response->throwUnless(fn (Response $response) => false);
// Викинути виняток, якщо відповідь має конкретний код статусу...
$response->throwIfStatus(403);
// Викинути виняток, якщо відповідь не має конкретного коду статусу...
$response->throwUnlessStatus(200);
// Викинути виняток, якщо сталася серверна помилка (статус >500)...
$response->throwIfServerError();
// Викинути виняток, якщо сталася клієнтська помилка (статус >400 і <500)...
$response->throwIfClientError();
return $response['user']['id'];
Екземпляр Illuminate\Http\Client\RequestException має публічну властивість $response, яка дозволяє дослідити повернуту відповідь.
Метод 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 символів під час логування або звітування. Щоб налаштувати чи вимкнути цю поведінку, скористайтеся методами truncateAt і dontTruncate під час налаштування зареєстрованої поведінки застосунку у файлі bootstrap/app.php:
use Illuminate\Http\Client\RequestException;
->registered(function (): void {
// Обрізати повідомлення винятків запиту до 240 символів...
RequestException::truncateAt(240);
// Вимкнути обрізання повідомлень винятків запиту...
RequestException::dontTruncate();
})
Як варіант, поведінку обрізання винятків можна налаштувати окремо для кожного запиту методом truncateExceptionsAt:
return Http::truncateExceptionsAt(240)->post(/* ... */);
Guzzle middleware
Оскільки HTTP-клієнт Laravel працює на Guzzle, ви можете скористатися Guzzle Middleware, щоб змінювати вихідний запит або досліджувати вхідну відповідь. Щоб змінити вихідний запит, зареєструйте Guzzle middleware методом withRequestMiddleware:
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');
Так само можна дослідити вхідну HTTP-відповідь, зареєструвавши middleware методом withResponseMiddleware:
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');
Глобальний middleware
Іноді потрібно зареєструвати middleware, який застосовується до кожного вихідного запиту та вхідної відповіді. Для цього є методи globalRequestMiddleware і globalResponseMiddleware. Зазвичай ці методи викликають у методі boot класу AppServiceProvider вашого застосунку:
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
Додаткові опції запиту Guzzle для вихідного запиту задаються методом withOptions. Метод withOptions приймає масив пар «ключ / значення»:
$response = Http::withOptions([
'debug' => true,
])->get('http://example.com/users');
Глобальні опції
Щоб налаштувати опції за замовчуванням для кожного вихідного запиту, скористайтеся методом globalOptions. Зазвичай цей метод викликають із методу boot класу AppServiceProvider вашого застосунку:
use Illuminate\Support\Facades\Http;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Http::globalOptions([
'allow_redirects' => false,
]);
}
Паралельні запити
Іноді потрібно виконати кілька HTTP-запитів паралельно. Тобто ви хочете, щоб кілька запитів вирушили одночасно, а не послідовно один за одним. Під час роботи з повільними HTTP-API це дає відчутний виграш у продуктивності.
Пул запитів
На щастя, це робиться методом pool. Метод 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();
Максимальну паралельність пулу запитів контролює аргумент concurrency методу pool. Це значення визначає максимальну кількість HTTP-запитів, які можуть одночасно перебувати в польоті під час обробки пулу:
$responses = Http::pool(fn (Pool $pool) => [
// ...
], concurrency: 5);
Якщо запит із пулу зазнає невдачі на рівні з'єднання (наприклад, таймаут чи збій DNS), відповідний елемент масиву $responses буде екземпляром Illuminate\Http\Client\ConnectionException, а не Response:
foreach ($responses as $response) {
if ($response instanceof Throwable) {
// Запиту не вдалося з'єднатися...
} elseif ($response->failed()) {
// Запит з'єднався, але отримав відповідь з помилкою...
}
}
Налаштування паралельних запитів
Метод pool не можна об'єднувати в ланцюжок з іншими методами HTTP-клієнта, як-от withHeaders чи middleware. Якщо потрібно застосувати власні заголовки або middleware до запитів у пулі, налаштуйте ці опції для кожного запиту в пулі:
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) {
// Пакет створено, але жодного запиту ще не ініціалізовано...
})->progress(function (Batch $batch, int|string $key, Response $response) {
// Окремий запит завершився успішно...
})->then(function (Batch $batch, array $results) {
// Усі запити завершилися успішно...
})->catch(function (Batch $batch, int|string $key, Response|RequestException|ConnectionException $response) {
// Виявлено невдачу запиту в пакеті...
})->finally(function (Batch $batch, array $results) {
// Пакет завершив виконання...
})->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();
Після того як batch запущено викликом методу send, додати до нього нові запити не можна. Спроба зробити це призведе до викидання винятку Illuminate\Http\Client\BatchInProgressException.
Максимальну паралельність пакета запитів контролює метод concurrency. Це значення визначає максимальну кількість HTTP-запитів, які можуть одночасно перебувати в польоті під час обробки пакета:
$responses = Http::batch(fn (Batch $batch) => [
// ...
])->concurrency(5)->send();
Перевірка пакетів
Екземпляр Illuminate\Http\Client\Batch, який передається в колбеки завершення пакета, має набір властивостей і методів для взаємодії з конкретним пакетом запитів і його перевірки:
// Кількість запитів, призначених пакету...
$batch->totalRequests;
// Кількість запитів, які ще не оброблено...
$batch->pendingRequests;
// Кількість запитів, які зазнали невдачі...
$batch->failedRequests;
// Кількість запитів, оброблених на цей момент...
$batch->processedRequests();
// Показує, чи пакет завершив виконання...
$batch->finished();
// Показує, чи є в пакеті невдалі запити...
$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) {
// Усі запити завершилися успішно...
})->defer();
Макроси
HTTP-клієнт Laravel дозволяє визначати «макроси» - плавний і виразний спосіб налаштувати типові шляхи запитів і заголовки для взаємодії із сервісами у вашому застосунку. Для початку визначте макрос у методі boot класу App\Providers\AppServiceProvider вашого застосунку:
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-клієнт Laravel не виняток. Метод fake фасада Http дозволяє наказати HTTP-клієнту повертати заглушки замість справжніх відповідей.
Підробка відповідей
Наприклад, щоб HTTP-клієнт повертав порожні відповіді з кодом статусу 200 на кожен запит, викличте метод fake без аргументів:
use Illuminate\Support\Facades\Http;
Http::fake();
$response = Http::post(/* ... */);
Підробка конкретних URL
Як варіант, методу fake можна передати масив. Ключі масиву мають відповідати шаблонам URL, які ви хочете підробити, а значення - їхнім відповідям. Символ * можна використовувати як символ підстановки. Щоб побудувати заглушки відповідей для цих ендпоінтів, скористайтеся методом response фасада Http:
Http::fake([
// Заглушка JSON-відповіді для ендпоінтів GitHub...
'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers),
// Заглушка рядкової відповіді для ендпоінтів Google...
'google.com/*' => Http::response('Hello World', 200, $headers),
]);
Будь-які запити до URL, які не підроблено, будуть виконані насправді. Якщо ви хочете задати запасний шаблон URL, який заглушить усі неспівпалі URL, використайте один символ *:
Http::fake([
// Заглушка JSON-відповіді для ендпоінтів GitHub...
'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),
// Заглушка рядкової відповіді для всіх інших ендпоінтів...
'*' => 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. Наказати HTTP-клієнту викинути виняток з'єднання можна методом 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([
// Заглушка серії відповідей для ендпоінтів GitHub...
'github.com/*' => Http::sequence()
->push('Hello World', 200)
->push(['foo' => 'bar'], 200)
->pushStatus(404),
]);
Коли всі відповіді в послідовності вичерпано, кожен наступний запит призведе до того, що послідовність відповідей викине виняток. Щоб задати відповідь за замовчуванням, яку слід повертати, коли послідовність порожня, скористайтеся методом whenEmpty:
Http::fake([
// Заглушка серії відповідей для ендпоінтів GitHub...
'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::assertSent після виклику Http::fake.
Метод 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 дозволяє зібрати всі запити та відповідні їм відповіді. Метод 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'),
]);
// Повертається відповідь "ok"...
Http::get('https://github.com/laravel/framework');
// Викидається виняток...
Http::get('https://laravel.com');
Іноді потрібно заборонити більшість сторонніх запитів, але дозволити виконання окремих. Для цього передайте масив шаблонів URL методу allowStrayRequests. Будь-який запит, що збігається з одним із заданих шаблонів, буде дозволено, а всі інші запити й далі викидатимуть виняток:
use Illuminate\Support\Facades\Http;
Http::preventStrayRequests();
Http::allowStrayRequests([
'http://127.0.0.1:5000/*',
]);
// Цей запит виконується...
Http::get('http://127.0.0.1:5000/generate');
// Викидається виняток...
Http::get('https://laravel.com');
Події
Під час надсилання HTTP-запитів Laravel запускає три події. Подія 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 ...
}
}
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.