中的處理常式與中介軟體AWS SDK for PHP第 3 版 - AWS SDK for PHP

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

中的處理常式與中介軟體AWS SDK for PHP第 3 版

AWS SDK for PHP的主要機制是透過處理常式中介軟體進行擴展。每種開發套件的用戶端類別均擁有 Aws\HandlerList 執行個體,其可透過用戶端的 getHandlerList() 方法存取。您可以擷取並修改用戶端的 HandlerList,藉此新增或移除用戶端行為。

處理常式

透過處理常式函數,使用者可以將命令與請求實際轉換為結果;且處理常式通常會傳送 HTTP 請求。為了增強自身行為,處理常式可以由中介軟體組成。處理常式是一個函數,它接受 Aws\CommandInterfacePsr\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); };

接著,您可以在用戶端的建構函式中提供 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 ]);

您也可以在建構完成後,使用 setHandlerAws\ClientInterface 方法,變更用戶端的處理常式。

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

若要在建構後變更多區域用戶端的處理常式,請使用useCustomHandler的方法Aws\MultiRegionClient

$multiRegionClient->useCustomHandler($myHandler);

模擬處理常式

我們建議您透過 MockHandler 來編寫使用開發套件的測試。您可以使用 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\CommandInterfacePsr\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

本開發套件會透過 Aws\HandlerList,善加管理執行命令時所使用的中介軟體與處理常式。每種開發套件的用戶端均擁有 HandlerList,且系統會複製此 HandlerList,並將其新增至用戶端所建立的每個命令。您可以在用戶端的 HandlerList 中新增一個中介軟體,藉此連接中介軟體與預設處理器,以用於用戶端所建立的每個命令。若要從特定命令中新增和移除中介軟體,則可以修改特定命令所擁有的 HandlerList

HandlerList 代表中介軟體堆疊,用以包裝處理常式。為了協助您管理中介軟體清單並安排包裝處理常式的順序,HandlerList 會將堆疊的中介軟體分解為指定步驟,而這些步驟即為傳輸命令生命週期的一部分:

  1. init - 新增預設參數

  2. validate - 驗證必要參數

  3. build - 將待傳送的 HTTP 請求序列化

  4. sign - 簽署序列化的 HTTP 請求

  5. <handler> (並非步驟,但會執行實際傳輸)

init

此生命週期步驟表示系統會將命令初始化,但尚未將請求序列化。這個步驟通常會用來將預設參數新增至命令。

您可以透過 initappendInit 方法,將中介軟體新增至 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

此生命週期步驟旨在驗證命令的輸入參數。

您可以透過 validateappendValidate 方法,將中介軟體新增至 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 請求。

您可以透過 buildappendBuild 方法,將中介軟體新增至 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 步驟。

您可以透過 signappendSign 方法,將中介軟體新增至 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');

可用的中介軟體

本開發套件提供多種中介軟體,以供您增強用戶端行為或查看命令的執行狀況。

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'] = 'mybucket'; // 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' => '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' );

現在當您執行命令時,系統會一併傳送該命令與自訂標頭。

重要

請注意,系統會在結束 build 步驟時,將中介軟體附加至處理常式清單。如此一來,便可確保系統在呼叫此中介軟體前,已經成功建立請求。

mapResult

如果您需要修改命令執行的結果,則 Aws\Middleware::mapResult 中介軟體相當實用。mapResult 函數所接受的呼叫,會應允 Aws\ResultInterface 引數並傳回 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; }) );

現在當您執行命令時,系統傳回的結果將會包含 foo 屬性。

歷程記錄

history 中介軟體有助於您測試開發套件是否成功執行預期的命令、成功傳送預期的 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

縱使開發套件提供多種 @http 選項,但處理常式僅需了解下列選項的使用方式:

除非將選項指定為選用,否則處理常式必須能夠處理選項,或必須傳回遭拒絕的 promise。

除了處理具體@http選項, 處理常式必須新增User-Agent標題採用以下形式,其中「3.X」可以替換為Aws\Sdk::VERSION和」HandlerSpecificData/version...」應該替換為處理程序特定的用戶代理字符串。

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