Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Laravel предоставляет выразительный, минимальный API вокруг клиента Guzzle HTTP, позволяя быстро выполнять исходящие HTTP-запросы для взаимодействия с другими веб-приложениями. Обертка Laravel вокруг Guzzle сосредоточена на его наиболее распространенных случаях использования и прекрасном опыте разработчика.
Прежде чем начать, убедитесь, что у вас установлен пакет Guzzle в качестве зависимости вашего приложения. По умолчанию Laravel автоматически включает эту зависимость. Однако, если вы ранее удалили пакет, вы можете установить его снова с помощью Composer:
composer require guzzlehttp/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) : array|mixed;$response->object() : object;$response->collect($key = null) : Illuminate\Support\Collection;$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
также реализует интерфейс ArrayAccess
PHP, что позволяет вам напрямую получать доступ к данным ответа 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
HTTP-клиент также позволяет вам создавать URL-адреса запросов с использованием спецификации шаблонов URI. Чтобы определить параметры URL, которые можно расширить с использованием вашего шаблона URI, вы можете использовать метод withUrlParameters
:
Http::withUrlParameters([ 'endpoint' => 'https://laravel.com', 'page' => 'docs', 'version' => '9.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
вы можете либо добавить строку запроса к 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')
Если вы хотите отправить данные с использованием типа контента 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')->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',]);
Можно указать учетные данные для базовой и дайджест-аутентификации, используя методы withBasicAuth
и withDigestAuth
соответственно:
// Базовая аутентификация... $response = Http::withBasicAuth('[email protected]', 'secret')->post(/* ... */);
// Дайджест-аутентификация... $response = Http::withDigestAuth('[email protected]', 'secret')->post(/* ... */);
Если вы хотите быстро добавить маркер доступа к заголовку Authorization
запроса, вы можете использовать метод withToken
:
$response = Http::withToken('token')->post(/* ... */);
Метод timeout
может использоваться для указания максимального количества секунд, ожидая ответа. По умолчанию HTTP-клиент завершит работу через 30 секунд:
$response = Http::timeout(3)->get(/* ... */);
Если установленный таймаут превышен, будет сгенерировано исключение Illuminate\Http\Client\ConnectionException
.
Можно указать максимальное количество секунд ожидания при попытке подключения к серверу с использованием метода connectTimeout
:
$response = Http::connectTimeout(3)->get(/* ... */);
Если вы хотите, чтобы HTTP-клиент автоматически повторил запрос в случае ошибки клиента или сервера, вы можете использовать метод retry
. Метод retry
принимает максимальное количество попыток выполнения запроса и количество миллисекунд, которое Laravel должна ждать между попытками:
$response = Http::retry(3, 100)->post(/* ... */);
При необходимости вы можете передать третий аргумент методу retry
. Третий аргумент должен быть вызываемым, которое определит, следует ли фактически предпринимать попытки повторения. Например, вы можете захотеть повторить запрос только в случае, если начальный запрос сталкивается с ConnectionException
:
use Exception;use Illuminate\Http\Client\PendingRequest; $response = Http::retry(3, 100, function (Exception $exception, PendingRequest $request) { return $exception instanceof ConnectionException;})->post(/* ... */);
Если попытка запроса завершится неудачей, возможно, вы захотите внести изменение в запрос перед новой попыткой. Это можно сделать, модифицировав аргумент запроса, предоставленный замыканию, предоставленному методу retry
. Например, вы можете хотеть повторить запрос с новым токеном авторизации, если первая попытка вернула ошибку аутентификации:
use Exception;use Illuminate\Http\Client\PendingRequest;use Illuminate\Http\Client\RequestException; $response = Http::withToken($this->getToken())->retry(2, 0, function (Exception $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);
// Выбросить исключение, если произошла ошибка и данный замыкание разрешается как истина... $response->throwIf(fn (Response $response) => true);
// Выбросить исключение, если произошла ошибка и данное условие ложно... $response->throwUnless($condition);
// Выбросить исключение, если произошла ошибка и данный замыкание разрешается как ложь... $response->throwUnless(fn (Response $response) => false);
// Выбросить исключение, если ответ имеет определенный код состояния... $response->throwIfStatus(403);
// Выбросить исключение, если ответ не имеет определенного кода состояния... $response->throwUnlessStatus(200);
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();
Поскольку HTTP-клиент Laravel работает на основе Guzzle, вы можете воспользоваться промежуточным ПО Guzzle для манипуляции исходящим запросом или анализа входящего ответа. Для манипуляции исходящим запросом зарегистрируйте промежуточное ПО Guzzle с помощью метода 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-ответ, зарегистрировав промежуточное ПО с помощью метода 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');
Иногда может потребоваться зарегистрировать промежуточное ПО, которое применяется к каждому исходящему запросу и входящему ответу. Для этого вы можете использовать методы 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, используя метод withOptions
. Метод withOptions
принимает массив пар ключ / значение:
$response = Http::withOptions([ 'debug' => true,])->get('http://example.com/users');
Иногда вам может потребоваться выполнить несколько 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();
Метод pool
нельзя цеплять с другими методами HTTP-клиента, такими как методы withHeaders
или 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'),]);
HTTP-клиент Laravel позволяет определять "макросы", которые могут служить выразительным и лаконичным механизмом настройки общих путей запросов и заголовков при взаимодействии с сервисами в вашем приложении. Для начала вы можете определить макрос в методе boot
класса App\Providers\AppServiceProvider
вашего приложения:
use Illuminate\Support\Facades\Http; /*** Загрузка любых служб приложения. */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(/* ... */);
В качестве альтернативы вы можете передать массив методу fake
. Ключи массива должны представлять шаблоны URL, которые вы хотите подделать, и их ассоциированные ответы. Символ *
можно использовать в качестве универсального символа. Любые запросы, выполненные по URL, который не был подделан, будут фактически выполнены. Вы можете использовать метод Http
response
для создания поддельных / фейковых ответов для этих конечных точек:
Http::fake([ // Заглушить JSON-ответ для точек доступа GitHub... 'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers), // Заглушить строковый ответ для точек доступа Google... 'google.com/*' => Http::response('Hello World', 200, $headers),]);
Если вы хотите указать запасной шаблон URL, который будет подделан для всех неподдельных URL, вы можете использовать один символ *
:
Http::fake([ // Заглушить JSON-ответ для точек доступа GitHub... 'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']), // Заглушить строковый ответ для всех остальных точек доступа... '*' => Http::response('Hello World', 200, ['Headers']),]);
Иногда вам может потребоваться указать, что один 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-клиент, подделаны в пределах вашего отдельного теста или полного набора тестов, вы можете вызвать метод 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');
При подделке ответов иногда может потребоваться проверить запросы, которые клиент получает, чтобы удостовериться, что ваше приложение отправляет правильные данные или заголовки. Вы можете сделать это, вызвав метод 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-docs.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();});
Laravel генерирует три события во время процесса отправки HTTP-запросов. Событие RequestSending
генерируется перед отправкой запроса, а событие ResponseReceived
- после получения ответа на данный запрос. Событие ConnectionFailed
генерируется, если не получен ответ на данный запрос.
События RequestSending
и ConnectionFailed
оба содержат общедоступное свойство $request
, которое можно использовать для проверки экземпляра Illuminate\Http\Client\Request
. Точно так же событие ResponseReceived
содержит свойства $request
и $response
, которые можно использовать для проверки экземпляров Illuminate\Http\Client\Request
и Illuminate\Http\Client\Response
. Вы можете зарегистрировать слушателей событий для этого события в вашем поставщике услуг App\Providers\EventServiceProvider
:
/*** Сопоставления слушателей событий для приложения. * * @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', ],];