本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
版本 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 ...