Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
Laravel proporciona una API expresiva y minimalista alrededor del cliente HTTP Guzzle, lo que le permite realizar rápidamente solicitudes HTTP salientes para comunicarse con otras aplicaciones web. El envoltorio de Laravel alrededor de Guzzle se centra en sus casos de uso más comunes y ofrece una maravillosa experiencia para el desarrollador.
Antes de comenzar, asegúrese de haber instalado el paquete Guzzle como una dependencia de su aplicación. De forma predeterminada, Laravel incluye automáticamente esta dependencia. Sin embargo, si anteriormente eliminó el paquete, puede instalarlo nuevamente a través de Composer:
composer require guzzlehttp/guzzle
Para realizar solicitudes, puede utilizar los métodos head
, get
, post
, put
, patch
y delete
proporcionados por la fachada Http
. Primero, veamos cómo hacer una solicitud básica GET
a otra URL:
use Illuminate\Support\Facades\Http; $response = Http::get('http://example.com');
El método get
devuelve una instancia de Illuminate\Http\Client\Response
, que proporciona una variedad de métodos que se pueden usar para inspeccionar la respuesta:
$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;
El objeto Illuminate\Http\Client\Response
también implementa la interfaz ArrayAccess
de PHP, lo que le permite acceder directamente a los datos de la respuesta JSON:
return Http::get('http://example.com/users/1')['name'];
Además de los métodos de respuesta enumerados anteriormente, se pueden usar los siguientes métodos para determinar si la respuesta tiene un código de estado dado:
$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
El cliente HTTP también le permite construir URLs de solicitud utilizando la especificación de plantillas URI. Para definir los parámetros de URL que se pueden expandir mediante su plantilla URI, puede usar el método withUrlParameters
:
Http::withUrlParameters([ 'endpoint' => 'https://laravel.com', 'page' => 'docs', 'version' => '9.x', 'topic' => 'validation',])->get('{+endpoint}/{page}/{version}/{topic}');
Si desea volcar la instancia de solicitud saliente antes de que se envíe y terminar la ejecución del script, puede agregar el método dd
al principio de su definición de solicitud:
return Http::dd()->get('http://example.com');
Por supuesto, es común al realizar solicitudes POST
, PUT
y PATCH
enviar datos adicionales con su solicitud, por lo que estos métodos aceptan un array de datos como su segundo argumento. De forma predeterminada, los datos se enviarán utilizando el tipo de contenido application/json
:
use Illuminate\Support\Facades\Http; $response = Http::post('http://example.com/users', [ 'name' => 'Steve', 'role' => 'Network Administrator',]);
Al realizar solicitudes GET
, puede agregar una cadena de consulta directamente a la URL o pasar un array de pares clave / valor como segundo argumento al método get
:
$response = Http::get('http://example.com/users', [ 'name' => 'Taylor', 'page' => 1,]);
Alternativamente, se puede usar el método withQueryParameters
:
Http::retry(3, 100)->withQueryParameters([ 'name' => 'Taylor', 'page' => 1,])->get('http://example.com/users')
Si desea enviar datos utilizando el tipo de contenido application/x-www-form-urlencoded
, debe llamar al método asForm
antes de realizar su solicitud:
$response = Http::asForm()->post('http://example.com/users', [ 'name' => 'Sara', 'role' => 'Privacy Consultant',]);
Puede usar el método withBody
si desea proporcionar un cuerpo de solicitud en crudo al realizar una solicitud. El tipo de contenido se puede proporcionar mediante el segundo argumento del método:
$response = Http::withBody( base64_encode($photo), 'image/jpeg')->post('http://example.com/photo');
Si desea enviar archivos como solicitudes multi-parte, debe llamar al método attach
antes de realizar su solicitud. Este método acepta el nombre del archivo y su contenido. Si es necesario, puede proporcionar un tercer argumento que se considerará el nombre del archivo:
$response = Http::attach( 'attachment', file_get_contents('photo.jpg'), 'photo.jpg')->post('http://example.com/attachments');
En lugar de pasar el contenido en crudo de un archivo, puede pasar un recurso de flujo:
$photo = fopen('photo.jpg', 'r'); $response = Http::attach( 'attachment', $photo, 'photo.jpg')->post('http://example.com/attachments');
Se pueden agregar encabezados a las solicitudes mediante el método withHeaders
. Este método withHeaders
acepta un array de pares clave / valor:
$response = Http::withHeaders([ 'X-First' => 'foo', 'X-Second' => 'bar'])->post('http://example.com/users', [ 'name' => 'Taylor',]);
Puede usar el método accept
para especificar el tipo de contenido que su aplicación espera en respuesta a su solicitud:
$response = Http::accept('application/json')->get('http://example.com/users');
Para mayor comodidad, puede usar el método acceptJson
para especificar rápidamente que su aplicación espera el tipo de contenido application/json
en respuesta a su solicitud:
$response = Http::acceptJson()->get('http://example.com/users');
El método withHeaders
fusiona nuevos encabezados en los encabezados existentes de la solicitud. Si es necesario, puede reemplazar por completo todos los encabezados usando el método replaceHeaders
:
$response = Http::withHeaders([ 'X-Original' => 'foo',])->replaceHeaders([ 'X-Replacement' => 'bar',])->post('http://example.com/users', [ 'name' => 'Taylor',]);
Puede especificar credenciales de autenticación básica y digest usando los métodos withBasicAuth
y withDigestAuth
, respectivamente:
// Autenticación básica... // Autenticación digest...
Si desea agregar rápidamente un token de portador al encabezado Authorization
de la solicitud, puede usar el método withToken
:
$response = Http::withToken('token')->post(/* ... */);
El método timeout
se puede usar para especificar el número máximo de segundos para esperar una respuesta. De forma predeterminada, el cliente HTTP agotará el tiempo después de 30 segundos:
$response = Http::timeout(3)->get(/* ... */);
Si se supera el tiempo de espera dado, se lanzará una instancia de Illuminate\Http\Client\ConnectionException
.
Puede especificar el tiempo máximo de espera mientras intenta conectarse a un servidor mediante el método connectTimeout
:
$response = Http::connectTimeout(3)->get(/* ... */);
Si desea que el cliente HTTP vuelva a intentar automáticamente la solicitud si ocurre un error del cliente o del servidor, puede usar el método retry
. El método retry
acepta el número máximo de veces que se debe intentar la solicitud y el número de milisegundos que Laravel debería esperar entre intentos:
$response = Http::retry(3, 100)->post(/* ... */);
Si es necesario, puede pasar un tercer argumento al método retry
. El tercer argumento debe ser una devolución de llamada que determine si los reintentos deben realizarse realmente. Por ejemplo, es posible que desee reintentar la solicitud solo si la solicitud inicial encuentra una ConnectionException
:
use Exception;use Illuminate\Http\Client\PendingRequest; $response = Http::retry(3, 100, function (Exception $exception, PendingRequest $request) { return $exception instanceof ConnectionException;})->post(/* ... */);
Si un intento de solicitud falla, es posible que desee realizar un cambio en la solicitud antes de realizar un nuevo intento. Puede lograr esto modificando el argumento de la solicitud proporcionado a la devolución de llamada que proporcionó al método retry
. Por ejemplo, es posible que desee volver a intentar la solicitud con un nuevo token de autorización si el primer intento devolvió un error de autenticación:
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(/* ... */);
Si todas las solicitudes fallan, se lanzará una instancia de Illuminate\Http\Client\RequestException
. Si desea deshabilitar este comportamiento, puede proporcionar un argumento throw
con un valor de false
. Cuando está deshabilitado, se devolverá la última respuesta recibida por el cliente después de que se hayan intentado todos los reintentos:
$response = Http::retry(3, 100, throw: false)->post(/* ... */);
Advertencia Si todas las solicitudes fallan debido a un problema de conexión, aún se lanzará una
Illuminate\Http\Client\ConnectionException
incluso cuando el argumentothrow
esté establecido enfalse
.
A diferencia del comportamiento predeterminado de Guzzle, el envoltorio del cliente HTTP de Laravel no arroja excepciones en errores del cliente o del servidor (respuestas de nivel 400
y 500
desde servidores). Puede determinar si se devolvió uno de estos errores mediante los métodos successful
, clientError
o serverError
:
// Determina si el código de estado es >= 200 y < 300...$response->successful(); // Determina si el código de estado es >= 400...$response->failed(); // Determina si la respuesta tiene un código de estado de nivel 400...$response->clientError(); // Determina si la respuesta tiene un código de estado de nivel 500...$response->serverError(); // Ejecuta inmediatamente la devolución de llamada dada si hay un error del cliente o del servidor...$response->onError(callable $callback);
Si tiene una instancia de respuesta y desea lanzar una instancia de Illuminate\Http\Client\RequestException
si el código de estado de la respuesta indica un error del cliente o del servidor, puede usar los métodos throw
o throwIf
:
use Illuminate\Http\Client\Response; $response = Http::post(/* ... */); // Lanza una excepción si ocurrió un error del cliente o del servidor...$response->throw(); // Lanza una excepción si ocurrió un error y la condición dada es verdadera...$response->throwIf($condition); // Lanza una excepción si ocurrió un error y la devolución de llamada dada se resuelve como verdadera...$response->throwIf(fn (Response $response) => true); // Lanza una excepción si ocurrió un error y la condición dada es falsa...$response->throwUnless($condition); // Lanza una excepción si ocurrió un error y la devolución de llamada dada se resuelve como falsa...$response->throwUnless(fn (Response $response) => false); // Lanza una excepción si la respuesta tiene un código de estado específico...$response->throwIfStatus(403); // Lanza una excepción a menos que la respuesta tenga un código de estado específico...$response->throwUnlessStatus(200); return $response['user']['id'];
La instancia de Illuminate\Http\Client\RequestException
tiene una propiedad pública $response
que le permitirá inspeccionar la respuesta devuelta.
El método throw
devuelve la instancia de respuesta si no ocurrió ningún error, lo que le permite encadenar otras operaciones en el método throw
:
return Http::post(/* ... */)->throw()->json();
Si desea realizar alguna lógica adicional antes de que se lance la excepción, puede pasar un cierre al método throw
. La excepción se lanzará automáticamente después de que se invoque el cierre, por lo que no es necesario volver a lanzar la excepción desde dentro del cierre:
use Illuminate\Http\Client\Response;use Illuminate\Http\Client\RequestException; return Http::post(/* ... */)->throw(function (Response $response, RequestException $e) { // ...})->json();
Dado que el cliente HTTP de Laravel está alimentado por Guzzle, puede aprovechar Guzzle Middleware para manipular la solicitud saliente o inspeccionar la respuesta entrante. Para manipular la solicitud saliente, registre un middleware de Guzzle a través del método 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');
Del mismo modo, puede inspeccionar la respuesta HTTP entrante registrando un middleware a través del método 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');
A veces, puede querer registrar un middleware que se aplique a cada solicitud saliente y respuesta entrante. Para lograr esto, puede usar los métodos globalRequestMiddleware
y globalResponseMiddleware
. Normalmente, estos métodos deberían invocarse en el método boot
del AppServiceProvider
de su aplicación:
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()));
Puede especificar opciones adicionales de solicitud de Guzzle mediante el método withOptions
. El método withOptions
acepta un array de pares clave / valor:
$response = Http::withOptions([ 'debug' => true,])->get('http://example.com/users');
En ocasiones, es posible que desee realizar múltiples solicitudes HTTP de manera concurrente. En otras palabras, desea que varias solicitudes se envíen al mismo tiempo en lugar de emitir las solicitudes secuencialmente. Esto puede llevar a mejoras sustanciales de rendimiento al interactuar con API HTTP lentas.
Afortunadamente, puede lograr esto utilizando el método pool
. El método pool
acepta un cierre que recibe una instancia de Illuminate\Http\Client\Pool
, lo que le permite agregar fácilmente solicitudes al conjunto de solicitudes para su envío:
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();
Como puede ver, cada instancia de respuesta se puede acceder según el orden en que se agregó al conjunto. Si lo desea, puede nombrar las solicitudes mediante el método as
, lo que le permite acceder a las respuestas correspondientes por nombre:
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();
El método pool
no se puede encadenar con otros métodos del cliente HTTP, como los métodos withHeaders
o middleware
. Si desea aplicar encabezados personalizados o middleware a las solicitudes agrupadas, debe configurar esas opciones en cada solicitud del conjunto:
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'),]);
El cliente HTTP de Laravel le permite definir "macros", que pueden servir como un mecanismo fluido y expresivo para configurar rutas y encabezados de solicitud comunes al interactuar con servicios en toda su aplicación. Para comenzar, puede definir la macro dentro del método boot
de la clase App\Providers\AppServiceProvider
de su aplicación:
use Illuminate\Support\Facades\Http; /** * Inicializa cualquier servicio de la aplicación. */public function boot(): void{ Http::macro('github', function () { return Http::withHeaders([ 'X-Example' => 'example', ])->baseUrl('https://github.com'); });}
Una vez que su macro haya sido configurada, puede invocarla desde cualquier lugar de su aplicación para crear una solicitud pendiente con la configuración especificada:
$response = Http::github()->get('/');
Muchos servicios de Laravel proporcionan funcionalidades para ayudarlo a escribir pruebas fácilmente y expresivamente, y el cliente HTTP de Laravel no es una excepción. El método fake
de la fachada Http
le permite instruir al cliente HTTP para que devuelva respuestas simuladas / ficticias cuando se realicen solicitudes.
Por ejemplo, para indicar al cliente HTTP que devuelva respuestas vacías con código de estado 200
para cada solicitud, puede llamar al método fake
sin argumentos:
use Illuminate\Support\Facades\Http; Http::fake(); $response = Http::post(/* ... */);
Alternativamente, puede pasar un array al método fake
. Las claves del array deben representar patrones de URL que desee simular y sus respuestas asociadas. El carácter *
se puede usar como un carácter comodín. Cualquier solicitud realizada a URL que no haya sido simulada se ejecutará realmente. Puede usar el método response
de la fachada Http
para construir respuestas simuladas / ficticias para estos puntos finales:
Http::fake([ // Simula una respuesta JSON para los puntos finales de GitHub... 'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers), // Simula una respuesta de cadena para los puntos finales de Google... 'google.com/*' => Http::response('Hello World', 200, $headers),]);
Si desea especificar un patrón de URL predeterminado que simulará todas las URL no coincidentes, puede usar un solo carácter *
:
Http::fake([ // Simula una respuesta JSON para los puntos finales de GitHub... 'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']), // Simula una respuesta de cadena para todos los demás puntos finales... '*' => Http::response('Hello World', 200, ['Headers']),]);
A veces, es posible que necesite especificar que una sola URL debe devolver una serie de respuestas simuladas en un orden específico. Puede lograr esto utilizando el método Http::sequence
para construir las respuestas:
Http::fake([ // Simula una serie de respuestas para los puntos finales de GitHub... 'github.com/*' => Http::sequence() ->push('Hello World', 200) ->push(['foo' => 'bar'], 200) ->pushStatus(404),]);
Cuando se consumen todas las respuestas en una secuencia de respuestas, cualquier solicitud adicional hará que la secuencia de respuestas lance una excepción. Si desea especificar una respuesta predeterminada que se debe devolver cuando una secuencia esté vacía, puede usar el método whenEmpty
:
Http::fake([ // Simula una serie de respuestas para los puntos finales de GitHub... 'github.com/*' => Http::sequence() ->push('Hello World', 200) ->push(['foo' => 'bar'], 200) ->whenEmpty(Http::response()),]);
Si desea simular una secuencia de respuestas pero no necesita especificar un patrón de URL específico que deba simularse, puede usar el método Http::fakeSequence
:
Http::fakeSequence() ->push('Hello World', 200) ->whenEmpty(Http::response());
Si necesita lógica más complicada para determinar qué respuestas devolver para ciertos puntos finales, puede pasar un cierre al método fake
. Este cierre recibirá una instancia de Illuminate\Http\Client\Request
y debería devolver una instancia de respuesta. Dentro de su cierre, puede realizar cualquier lógica necesaria para determinar qué tipo de respuesta devolver:
use Illuminate\Http\Client\Request; Http::fake(function (Request $request) { return Http::response('Hello World', 200);});
Si desea asegurarse de que todas las solicitudes enviadas a través del cliente HTTP hayan sido simuladas en su prueba individual o suite de pruebas completa, puede llamar al método preventStrayRequests
. Después de llamar a este método, cualquier solicitud que no tenga una respuesta simulada correspondiente lanzará una excepción en lugar de realizar la solicitud HTTP real:
use Illuminate\Support\Facades\Http; Http::preventStrayRequests(); Http::fake([ 'github.com/*' => Http::response('ok'),]); // Se devuelve una respuesta "ok"...Http::get('https://github.com/laravel/framework'); // Se lanza una excepción...Http::get('https://laravel.com');
Al simular respuestas, ocasionalmente puede desear inspeccionar las solicitudes que recibe el cliente para asegurarse de que su aplicación esté enviando los datos o encabezados correctos. Puede lograr esto llamando al método Http::assertSent
después de llamar a Http::fake
.
El método assertSent
acepta un cierre que recibirá una instancia de Illuminate\Http\Client\Request
y debería devolver un valor booleano que indique si la solicitud cumple con sus expectativas. Para que la prueba sea exitosa, al menos una solicitud debe haberse realizado coincidiendo con las expectativas dadas:
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';});
Si es necesario, puede afirmar que no se envió una solicitud específica mediante el método 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';});
Puede usar el método assertSentCount
para afirmar cuántas solicitudes se "enviaron" durante la prueba:
Http::fake(); Http::assertSentCount(5);
O puede usar el método assertNothingSent
para afirmar que no se envió ninguna solicitud durante la prueba:
Http::fake(); Http::assertNothingSent();
Puede usar el método recorded
para recopilar todas las solicitudes y sus respuestas correspondientes. El método recorded
devuelve una colección de arrays que contienen instancias de Illuminate\Http\Client\Request
e 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];
Además, el método recorded
acepta un cierre que recibirá una instancia de Illuminate\Http\Client\Request
e Illuminate\Http\Client\Response
y se puede usar para filtrar pares de solicitudes / respuestas según sus expectativas:
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 dispara tres eventos durante el proceso de envío de solicitudes HTTP. El evento RequestSending
se dispara antes de que se envíe una solicitud, mientras que el evento ResponseReceived
se dispara después de recibir una respuesta para una solicitud dada. El evento ConnectionFailed
se dispara si no se recibe ninguna respuesta para una solicitud dada.
Los eventos RequestSending
y ConnectionFailed
contienen ambos una propiedad pública $request
que puede usar para inspeccionar la instancia de Illuminate\Http\Client\Request
. Del mismo modo, el evento ResponseReceived
contiene una propiedad $request
y una propiedad $response
que se pueden usar para inspeccionar las instancias de Illuminate\Http\Client\Request
e Illuminate\Http\Client\Response
, respectivamente. Puede registrar escuchadores de eventos para este evento en su proveedor de servicios de eventos App\Providers\EventServiceProvider
:
/** * Los mapeos de escuchadores de eventos para la aplicación. * * @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', ],];