本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
第 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);
注意
若要在建立多區域用戶端之後變更該用戶端的處理常式,請使用 useCustomHandler
的方法Aws\MultiRegionClient
。
$multiRegionClient->useCustomHandler($myHandler);
模擬處理常式
我們建議您在撰寫使用 的測試MockHandler
時使用 SDK。您可以使用 Aws\MockHandler
以傳回模擬結果或擲回模擬例外狀況。您查詢結果或例外狀況,並將它們FIFO依序 MockHandler 取消佇列。
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
-
此生命週期步驟旨在驗證命令的輸入參數。
您可以透過
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');
- sign
-
此生命週期步驟通常用於簽署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
當您需要在命令序列化為HTTP請求之前修改命令時,Aws\Middleware::mapCommand
中介軟體很有用。例如,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);
當您執行通過 history 中介軟體的請求後,即可檢查歷史記錄容器。
// 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
選項,但處理常式只需要知道如何使用下列選項:
-
decode_content (選用)
-
progress (選用)
-
synchronous (選用)
-
stream (選用)
-
http_stats_receiver (選用) - 如果使用 stats 組態參數請求,則使用與HTTP傳輸統計資料關聯陣列調用的函數。
除非選項指定為選用,否則處理常式MUST可以處理該選項,或MUST傳回拒絕的承諾。
除了處理特定@http
選項之外,處理常式還會MUST新增採用下列格式的User-Agent
標頭,其中「3.X」可以取代為 Aws\Sdk::VERSION
,而「HandlerSpecificData/版本 ...」應該取代為處理常式特定的 User-Agent 字串。
User-Agent: aws-sdk-php/3.X HandlerSpecificData/version ...