本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
版本 3 中的处理程序和中间件 AWS SDK for PHP
扩展的主要机制 AWS SDK for PHP 是通过处理程序和中间件。每个SDK客户端类都拥有一个可通过客户端getHandlerList()
方法访问的Aws\HandlerList
实例。您可以检索客户端的 HandlerList
,并对其进行修改来添加或删除客户端行为。
处理程序
处理程序是一个将命令和请求实际转换为结果的函数。处理程序通常会发送HTTP请求。处理程序可由中间件组成,以增强行为。处理程序是一个函数,它接受 Aws\CommandInterface
和 Psr\Http\Message\RequestInterface
,并返回用 Aws\ResultInterface
执行或因 Aws\Exception\AwsException
原因而被拒绝的 Promise。
以下处理程序的每次调用均返回相同的模拟结果。
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); };
然后,您可以通过在SDK客户端的构造函数中提供一个handler
选项,将此处理程序用于客户端。
// Set the handler of the client in the constructor $s3 = new Aws\S3\S3Client([ 'region' => 'us-east-1', 'version' => '2006-03-01', 'handler' => $myHandler ]);
您还可以在客户端构造完成后使用 setHandler
的Aws\ClientInterface
方法更改其处理程序。
// Set the handler of the client after it is constructed $s3->getHandlerList()->setHandler($myHandler);
注意
要在多区域客户端构造完成后更改其处理程序,请使用 Aws\MultiRegionClient
的 useCustomHandler
方法。
$multiRegionClient->useCustomHandler($myHandler);
模拟处理程序
我们建议在编写使用. 的测试MockHandler
时使用SDK。您可以使用 Aws\MockHandler
返回模拟结果或引发模拟异常。您将结果或异常排入队列,然后按顺 MockHandler 序将它们出队。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();
中间件
中间件是一类特殊的高级函数,可对传输命令的行为进行增强,并委托给“下一个”处理程序。中间件函数接受 Aws\CommandInterface
和 Psr\Http\Message\RequestInterface
,并返回用 Aws\ResultInterface
执行或因 Aws\Exception\AwsException
原因而被拒绝的 Promise。
中间件是更高阶的函数,可修改经过中间件传递的命令、请求或结果。中间件具有以下形式。
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; }; }; };
中间件接收要执行的命令和可选的请求对象。中间件可增强请求和命令,或将它们保留原样。然后中间件会调用链条中的下一个处理程序,或选择将下一个处理程序短路并返回 Promise。调用下一个处理程序创建的 Promise,可使用 Promise 的 then
方法进行增强,在将 Promise 返回中间件组之前,修改最终结果或错误。
HandlerList
SDK使用Aws\HandlerList
来管理执行命令时使用的中间件和处理程序。每个SDK客户机都拥有一个HandlerList
,HandlerList
它会被克隆并添加到客户端创建的每个命令中。您可以将中间件添加到客户端的 HandlerList
,为客户端创建的每条命令附加要使用的中间件和默认处理程序。您可以修改特定命令的 HandlerList
,添加或删除特定命令的中间件。
HandlerList
表示用于包装处理程序的一组中间件。HandlerList
可将中间件组拆分为一些具名步骤,表示传输命令的生命周期中的各个部分。这样有助于管理中间件的列表,以及包装处理程序的顺序。
-
init
- 添加默认参数 -
validate
- 验证必要参数 -
build
-序列化发送HTTP请求 -
sign
-签署序列化请求 HTTP -
<handler>(不是一个步骤,但执行实际传输过程)
- init
-
生命周期中的这个步骤表示命令的初始化,以及尚未序列化的请求。此步骤通常用于在命令中添加默认参数。
您可以使用
init
和appendInit
方法在prependInit
步骤中添加中间件,其中appendInit
将中间件添加到prepend
列表的最后,prependInit
将中间件添加到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');
- 验证
-
生命周期中的这个步骤用于验证命令的输入参数。
您可以使用
validate
和appendValidate
方法在prependValidate
步骤中添加中间件,其中appendValidate
将中间件添加到validate
列表的最后,prependValidate
将中间件添加到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
-
此生命周期步骤用于序列化对正在执行的命令的HTTP请求。下游生命周期事件将收到命令和 PSR -7 HTTP 请求。
您可以使用
build
和appendBuild
方法在prependBuild
步骤中添加中间件,其中appendBuild
将中间件添加到build
列表的最后,prependBuild
将中间件添加到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');
- 签名
-
此生命周期步骤通常用于在HTTP请求通过网络发送之前对其进行签名。为避免签名错误,通常应避免在HTTP请求签名后对其进行变更。
这是处理程序传输HTTP请求
HandlerList
之前的最后一步。您可以使用
sign
和appendSign
方法在prependSign
步骤中添加中间件,其中appendSign
将中间件添加到sign
列表的最后,prependSign
将中间件添加到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');
可用中间件
SDK提供了几个中间件,您可以使用这些中间件来增强客户端的行为或观察命令的执行情况。
mapCommand
当您需要在命令序列化为请求之前修改命令时,Aws\Middleware::mapCommand
中间件非常有用。HTTP例如,可使用 mapCommand
执行验证或添加默认参数。mapCommand
函数接受的可调用函数可接受 Aws\CommandInterface
对象并返回 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'] = 'amzn-s3-demo-bucket'; // Be sure to return the command! return $command; }), 'add-param' );
mapRequest
如果您需要修改已序列化但尚未发送的请求,Aws\Middleware::mapRequest
中间件很有用。例如,这可用于向请求添加自定义HTTP标头。mapRequest
函数接受的可调用函数可接受 Psr\Http\Message\RequestInterface
参数并返回 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' => 'amzn-s3-demo-bucket' ]); // 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' );
当执行命令时,会随自定义标题发送。
重要
请注意,中间件是在 build
步骤的最后追加到处理程序列表中的。这是为了确保在调用中间件之前生成请求。
mapResult
如果您需要修改命令执行的结果,Aws\Middleware::mapResult
中间件很有用。mapResult
函数接受的可调用函数可接受 Aws\ResultInterface
参数并返回 Aws\ResultInterface
对象。
use Aws\Middleware; use Aws\ResultInterface; $command = $s3Client->getCommand('HeadObject', [ 'Key' => 'test', 'Bucket' => 'amzn-s3-demo-bucket' ]); $command->getHandlerList()->appendSign( Middleware::mapResult(function (ResultInterface $result) { // Add a custom value to the result $result['foo'] = 'bar'; return $result; }) );
命令执行后,返回的结果中将包含 foo
属性。
历史记录
history
中间件对于测试他们是否SDK执行了预期的命令、发送了预期的HTTP请求以及是否收到了预期的结果非常有用。这个中间件与 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));
在清除条目之前,Aws\History
历史记录容器中默认可存储 10 条记录,您可以将要保留的条目数量传递到构造函数中,从而自定义条目数量。
// Create a history container that stores 20 entries $history = new History(20);
您可以在执行传递历史记录中间件的请求之后,检查历史记录容器。
// 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
tap
中间件可用作观察工具。您可以使用此中间件,在通过中间件链条发送命令时调用函数。tap
函数接受的可调用函数可接受 Aws\CommandInterface
,以及被执行的可选 Psr\Http\Message\RequestInterface
。
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"; } } );
创建自定义处理程序
处理程序只是一个接受 Aws\CommandInterface
对象和 Psr\Http\Message\RequestInterface
对象的函数,它可返回由 GuzzleHttp\Promise\PromiseInterface
满足、或由 Aws\ResultInterface
拒绝的 Aws\Exception\AwsException
。
尽管SDK有多个@http
选项,但处理程序只需要知道如何使用以下选项即可:
除非将该选项指定为可选,否则处理程序MUST能够处理该选项或MUST返回被拒绝的承诺。
除了处理特定@http
选项外,处理程序还会MUST添加一个采用以下格式的User-Agent
标头,其中 “3.X” 可以替换为,“HandlerSpecificData/version...” 应替换为处理程序特定的用户代理字符串。Aws\Sdk::VERSION
User-Agent: aws-sdk-php/3.X HandlerSpecificData/version ...