Controladores y middleware en la versión 3 de AWS SDK for PHP - AWS SDK for PHP

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Controladores y middleware en la versión 3 de AWS SDK for PHP

El mecanismo principal para ampliar AWS SDK for PHP es mediante controladores y middleware. Cada clase del cliente del SDK posee una instancia Aws\HandlerList a la que se puede obtener acceso utilizando el método getHandlerList() de un cliente. Puede recuperar la HandlerList de un cliente y modificarla para añadir o eliminar el comportamiento del cliente.

Controladores

Un controlador es una función que realiza la transformación real de un comando y una solicitud en un resultado. Un controlador suele enviar solicitudes HTTP. Los controladores pueden incluir middleware para aumentar su comportamiento. Un controlador es una función que acepta una Aws\CommandInterface y una Psr\Http\Message\RequestInterface y devuelve una promesa que se cumple con una Aws\ResultInterface o se rechaza con un motivo Aws\Exception\AwsException.

A continuación se presenta un controlador que devuelve el mismo resultado simulado para cada llamada.

use Aws\CommandInterface; use Aws\Result; use Psr\Http\Message\RequestInterface; use GuzzleHttp\Promise; $myHandler = function (CommandInterface $cmd, RequestInterface $request) { $result = new Result(['foo' => 'bar']); return Promise\promise_for($result); };

A continuación, puede utilizar este controlador con un cliente del SDK proporcionando una opción handler en el constructor de un cliente.

// Set the handler of the client in the constructor $s3 = new Aws\S3\S3Client([ 'region' => 'us-east-1', 'version' => '2006-03-01', 'handler' => $myHandler ]);

También puede cambiar el controlador de un cliente después de crearlo utilizando el método setHandler de una Aws\ClientInterface.

// Set the handler of the client after it is constructed $s3->getHandlerList()->setHandler($myHandler);
nota

Para cambiar el controlador de un cliente después de crearlo utilizando el método useCustomHandler de una Aws\MultiRegionClient.

$multiRegionClient->useCustomHandler($myHandler);

Controlador simulado

Le recomendamos que utilice el MockHandler para escribir pruebas que utilicen el SDK. Puede utilizar el parámetro Aws\MockHandler para devolver los resultados simulados o lanzar excepciones simuladas. El usuario debe poner los resultados o las excepciones a la cola, y MockHandler los saca de la cola siguiendo el orden FIFO.

use Aws\Result; use Aws\MockHandler; use Aws\DynamoDb\DynamoDbClient; use Aws\CommandInterface; use Psr\Http\Message\RequestInterface; use Aws\Exception\AwsException; $mock = new MockHandler(); // Return a mocked result $mock->append(new Result(['foo' => 'bar'])); // You can provide a function to invoke; here we throw a mock exception $mock->append(function (CommandInterface $cmd, RequestInterface $req) { return new AwsException('Mock exception', $cmd); }); // Create a client with the mock handler $client = new DynamoDbClient([ 'region' => 'us-west-2', 'version' => 'latest', 'handler' => $mock ]); // Result object response will contain ['foo' => 'bar'] $result = $client->listTables(); // This will throw the exception that was enqueued $client->listTables();

Middleware

El middleware es un tipo especial de función de alto nivel que aumenta el comportamiento de la transferencia de un comando y lo delega al "siguiente" controlador. Las funciones de middleware aceptan una Aws\CommandInterface y una Psr\Http\Message\RequestInterface y devuelven una promesa que se cumple con una Aws\ResultInterface o se rechaza con un motivo Aws\Exception\AwsException.

Un middleware es una función de orden superior que modifica un comando, solicitud o resultado al pasar por el middleware. Un middleware tiene el siguiente aspecto.

use Aws\CommandInterface; use Psr\Http\Message\RequestInterface; $middleware = function () { return function (callable $handler) use ($fn) { return function ( CommandInterface $command, RequestInterface $request = null ) use ($handler, $fn) { // Do something before calling the next handler // ... $promise = $fn($command, $request); // Do something in the promise after calling the next handler // ... return $promise; }; }; };

Un middleware recibe un comando a ejecutar y un objeto Request opcional. El middleware puede elegir aumentar la solicitud y el comando o dejarlas tal y como están. A continuación, un middleware invoca al siguiente controlador de la cadena o puede optar por cortocircuitar el siguiente controlador y devolver una promesa. La promesa que se crea invocando el siguiente controlador también se puede aumentar utilizando el método then de la promesa para modificar el posible resultado o error antes de devolver la promesa a la pila de middleware.

HandlerList

El SDK utiliza una Aws\HandlerList para administrar el middleware y los controladores utilizados al ejecutar un comando. Cada cliente del SDK posee una HandlerList y dicha HandlerList se clona y se agrega a cada comando que crea un cliente. Puede asociar un middleware y el controlador predeterminado que se va a utilizar para cada comando creado por un cliente añadiendo un middleware a la HandlerList del cliente. Puede añadir y eliminar middleware de comandos específicos modificando la HandlerList propiedad de un comando específico.

Una HandlerList representa una pila de middleware que se utiliza para encapsular un controlador. Para ayudar a administrar la lista de middleware y el orden en que encapsulan un controlador, la HandlerList divide la pila en pasos denominados que representan partes del ciclo de vida de la transferencia de un comando:

  1. init: añade parámetros predeterminados

  2. validate: valida los parámetros obligatorios

  3. build: serializa una solicitud HTTP para enviarla

  4. sign: firma la solicitud HTTP serializada

  5. <controlador> (no es un paso pero ejecuta la transferencia real)

init

Este paso del ciclo de vida representa la inicialización de un comando. Aún no se ha serializado ninguna solicitud. Este paso se suele utilizar para añadir los parámetros predeterminados a un comando.

Puede añadir un middleware al paso init con los métodos appendInit y prependInit, donde appendInit añade el middleware al final de la lista prepend mientras que prependInit añade el middleware al principio de la lista prepend.

use Aws\Middleware; $middleware = Middleware::tap(function ($cmd, $req) { // Observe the step }); // Append to the end of the step with a custom name $client->getHandlerList()->appendInit($middleware, 'custom-name'); // Prepend to the beginning of the step $client->getHandlerList()->prependInit($middleware, 'custom-name');
validar

Este paso del ciclo de vida se utiliza para validar los parámetros de entrada de un comando.

Puede añadir un middleware al paso validate con los métodos appendValidate y prependValidate, donde appendValidate añade el middleware al final de la lista validate mientras que prependValidate añade el middleware al principio de la lista validate.

use Aws\Middleware; $middleware = Middleware::tap(function ($cmd, $req) { // Observe the step }); // Append to the end of the step with a custom name $client->getHandlerList()->appendValidate($middleware, 'custom-name'); // Prepend to the beginning of the step $client->getHandlerList()->prependValidate($middleware, 'custom-name');
build

Este paso del ciclo de vida se utiliza para serializar una solicitud HTTP para el comando que se está ejecutando. Los eventos del ciclo de vida posteriores recibirán un comando y una solicitud HTTP PSR-7.

Puede añadir un middleware al paso build con los métodos appendBuild y prependBuild, donde appendBuild añade el middleware al final de la lista build mientras que prependBuild añade el middleware al principio de la lista build.

use Aws\Middleware; $middleware = Middleware::tap(function ($cmd, $req) { // Observe the step }); // Append to the end of the step with a custom name $client->getHandlerList()->appendBuild($middleware, 'custom-name'); // Prepend to the beginning of the step $client->getHandlerList()->prependBuild($middleware, 'custom-name');
sign

Este paso del ciclo de vida se suele utilizar para firmar solicitudes HTTP antes de que se envíen a través de la red. Debe abstenerse de realizar cambios en una solicitud HTTP cuando ya esté firmada para evitar errores de firma.

Este es el último paso de la HandlerList antes de que un controlador transfiera la solicitud HTTP.

Puede añadir un middleware al paso sign con los métodos appendSign y prependSign, donde appendSign añade el middleware al final de la lista sign mientras que prependSign añade el middleware al principio de la lista sign.

use Aws\Middleware; $middleware = Middleware::tap(function ($cmd, $req) { // Observe the step }); // Append to the end of the step with a custom name $client->getHandlerList()->appendSign($middleware, 'custom-name'); // Prepend to the beginning of the step $client->getHandlerList()->prependSign($middleware, 'custom-name');

Middleware disponible

El SDK proporciona varios middleware que puede utilizar para aumentar el comportamiento de un cliente o para observar la ejecución de un comando.

mapCommand

El middleware Aws\Middleware::mapCommand resulta útil cuando hay que modificar un comando antes de que se serialice como solicitud HTTP. Por ejemplo, mapCommand se puede utilizar para llevar a cabo una validación o para añadir parámetros predeterminados. La función mapCommand acepta una función invocable que admite un objeto Aws\CommandInterface y devuelve un objeto Aws\CommandInterface.

use Aws\Middleware; use Aws\CommandInterface; // Here we've omitted the require Bucket parameter. We'll add it in the // custom middleware. $command = $s3Client->getCommand('HeadObject', ['Key' => 'test']); // Apply a custom middleware named "add-param" to the "init" lifecycle step $command->getHandlerList()->appendInit( Middleware::mapCommand(function (CommandInterface $command) { $command['Bucket'] = 'mybucket'; // Be sure to return the command! return $command; }), 'add-param' );

mapRequest

El middleware Aws\Middleware::mapRequest resulta útil cuando hay que modificar una solicitud después de serializarla pero antes de enviarla. Por ejemplo, se puede utilizar para añadir encabezados HTTP personalizados a una solicitud. La función mapRequest acepta una función invocable que admite un argumento Psr\Http\Message\RequestInterface y devuelve un objeto Psr\Http\Message\RequestInterface.

use Aws\Middleware; use Psr\Http\Message\RequestInterface; // Create a command so that we can access the handler list $command = $s3Client->getCommand('HeadObject', [ 'Key' => 'test', 'Bucket' => 'mybucket' ]); // Apply a custom middleware named "add-header" to the "build" lifecycle step $command->getHandlerList()->appendBuild( Middleware::mapRequest(function (RequestInterface $request) { // Return a new request with the added header return $request->withHeader('X-Foo-Baz', 'Bar'); }), 'add-header' );

Ahora al ejecutar el comando, se envía con el encabezado personalizado.

importante

Tenga en cuenta que el middleware se adjuntó a la lista de controladores al final del paso build. De este modo, se garantiza que se cree una solicitud antes de invocar este middleware.

mapResult

El middleware Aws\Middleware::mapResult resulta útil para modificar el resultado de una ejecución del comando. La función mapResult acepta una función invocable que admite un argumento Aws\ResultInterface y devuelve un objeto Aws\ResultInterface.

use Aws\Middleware; use Aws\ResultInterface; $command = $s3Client->getCommand('HeadObject', [ 'Key' => 'test', 'Bucket' => 'mybucket' ]); $command->getHandlerList()->appendSign( Middleware::mapResult(function (ResultInterface $result) { // Add a custom value to the result $result['foo'] = 'bar'; return $result; }) );

Ahora cuando se ejecute el comando, el resultado incluirá un atributo foo.

historial

El middleware history es útil para probar que el SDK ejecuta los comandos previstos, envía las solicitudes HTTP esperadas y recibe los resultados previstos. Se trata básicamente de un middleware que actúa de forma similar al historial de un navegador web.

use Aws\History; use Aws\Middleware; $ddb = new Aws\DynamoDb\DynamoDbClient([ 'version' => 'latest', 'region' => 'us-west-2' ]); // Create a history container to store the history data $history = new History(); // Add the history middleware that uses the history container $ddb->getHandlerList()->appendSign(Middleware::history($history));

Un contenedor de historiales Aws\History almacena 10 entradas de forma predeterminada antes de purgar las entradas. Puede personalizar el número de entradas transfiriendo el número de entradas que desea conservar en el constructor.

// Create a history container that stores 20 entries $history = new History(20);

Puede examinar el contenedor de historiales después de ejecutar las solicitudes que transfieren el middleware del historial.

// The object is countable, returning the number of entries in the container count($history); // The object is iterable, yielding each entry in the container foreach ($history as $entry) { // You can access the command that was executed var_dump($entry['command']); // The request that was serialized and sent var_dump($entry['request']); // The result that was received (if successful) var_dump($entry['result']); // The exception that was received (if a failure occurred) var_dump($entry['exception']); } // You can get the last Aws\CommandInterface that was executed. This method // will throw an exception if no commands have been executed. $command = $history->getLastCommand(); // You can get the last request that was serialized. This method will throw an exception // if no requests have been serialized. $request = $history->getLastRequest(); // You can get the last return value (an Aws\ResultInterface or Exception). // The method will throw an exception if no value has been returned for the last // executed operation (e.g., an async request has not completed). $result = $history->getLastReturn(); // You can clear out the entries using clear $history->clear();

tap

El middleware tap se utiliza como observador. Puede utilizar este middleware para invocar a funciones al enviar los comandos a través de la cadena de middleware. La función tap acepta una función invocable que admite la Aws\CommandInterface y una Psr\Http\Message\RequestInterface opcional que se está ejecutando.

use Aws\Middleware; $s3 = new Aws\S3\S3Client([ 'region' => 'us-east-1', 'version' => '2006-03-01' ]); $handlerList = $s3->getHandlerList(); // Create a tap middleware that observes the command at a specific step $handlerList->appendInit( Middleware::tap(function (CommandInterface $cmd, RequestInterface $req = null) { echo 'About to send: ' . $cmd->getName() . "\n"; if ($req) { echo 'HTTP method: ' . $request->getMethod() . "\n"; } } );

Crear controladores personalizados

Un controlador es simplemente una función que acepta un objeto Aws\CommandInterface y un objeto Psr\Http\Message\RequestInterface, y que devuelve una GuzzleHttp\Promise\PromiseInterface que se cumple con una Aws\ResultInterface o se rechaza con una Aws\Exception\AwsException.

Aunque el SDK tiene varias opciones @http, un controlador solo necesita saber cómo utilizar las siguientes opciones:

A menos que la opción se especifique como opcional, un controlador DEBE controlar la opción o devolver una promesa rechazada.

Además de la gestión de opciones @http específicas, un controlador DEBE añadir un encabezado User-Agent que tiene el siguiente formato, donde "3.X" se puede reemplazar por Aws\Sdk::VERSION y "HandlerSpecificData/version..." debe sustituirse por la cadena User-Agent específica del controlador.

User-Agent: aws-sdk-php/3.X HandlerSpecificData/version ...