

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS SDK for PHP 버전 3의 핸들러 및 미들웨어
<a name="guide_handlers-and-middleware"></a>

AWS SDK for PHP를 확장하는 기본 메커니즘은 **핸들러** 및 **미들웨어**를 사용하는 것입니다. 각 SDK 클라이언트 클래스에는 클라이언트의 `Aws\HandlerList` 메서드를 통해 액세스할 수 있는 `getHandlerList()` 인스턴스가 있습니다. 클라이언트의 `HandlerList`를 검색한 후 클라이언트 동작을 추가하거나 제거하도록 수정할 수 있습니다.

## 핸들러
<a name="handlers"></a>

핸들러는 명령 및 요청을 결과로 실제로 변환하는 함수입니다. 핸들러는 일반적으로 HTTP 요청을 전송합니다. 핸들러를 미들웨어와 함께 구성하여 동작을 강화할 수 있습니다. 핸들러는 `Aws\CommandInterface` 및 `Psr\Http\Message\RequestInterface`를 받아 `Aws\ResultInterface`와 함께 실행되거나 `Aws\Exception\AwsException` 이유와 함께 거부되는 promise를 반환하는 함수입니다.

다음은 각 호출에 대해 동일한 모의(mock) 결과를 반환하는 핸들러입니다.

```
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` 옵션을 제공하여 SDK 클라이언트에서 이 핸들러를 사용할 수 있습니다.

```
// 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);
```

### 모의(mock) 핸들러
<a name="mock-handler"></a>

SDK를 사용하는 테스트를 작성할 경우 `MockHandler`를 사용하는 것이 좋습니다. `Aws\MockHandler`를 사용하여 모의(mock) 결과를 반환하거나 모의(mock) 예외를 발생할 수 있습니다. 결과 또는 예외를 대기열에 넣으면 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();
```

## 미들웨어
<a name="middleware"></a>

미들웨어는 특수 유형의 상위 수준 함수로서, 명령을 전송하는 동작을 강화하고 “다음” 핸들러에 위임합니다. 미들웨어 함수는 `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를 해당하는 `then` 메서드로 보강하여 이벤트 결과 또는 오류를 수정한 후 promise를 미들웨어의 스택에 다시 반환할 수 있습니다.

### HandlerList
<a name="handlerlist"></a>

SDK는 `Aws\HandlerList`를 사용하여 명령을 실행할 때 사용되는 미들웨어와 핸들러를 관리합니다. 각 SDK 클라이언트에는 `HandlerList`가 있고, 이 `HandlerList`는 복제되어 클라이언트에서 생성되는 각 명령에 추가됩니다. 미들웨어와 기본 핸들러를 연결한 후 미들웨어를 클라이언트의 `HandlerList`에 추가하여 클라이언트에서 생성되는 각 명령에서 사용할 수 있습니다. 특정 명령이 소유한 `HandlerList`를 수정하여 해당 명령에서 미들웨어를 추가 및 제거할 수 있습니다.

`HandlerList`는 **핸들러**를 래핑하는 데 사용되는 미들웨어 스택을 나타냅니다. 미들웨어 목록과 핸들러를 래핑하는 순서를 관리할 수 있도록 `HandlerList`는 명령을 전송하는 수명 주기의 일부를 나타내는 명명된 단계로 미들웨어 스택을 분할합니다.

1.  `init` - 기본 파라미터 추가

1.  `validate` - 필수 파라미터 확인

1.  `build` - 전송을 위한 HTTP 요청 직렬화

1.  `sign` - 직렬화된 HTTP 요청에 서명

1. <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');
```

**빌드**  
이 수명 주기 단계는 실행 중인 명령에 대한 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');
```

### 사용 가능한 미들웨어
<a name="available-middleware"></a>

SDK는 클라이언트의 동작을 보강하거나 명령의 실행을 관찰하는 데 사용할 수 있는 다양한 미들웨어를 제공합니다.

#### mapCommand
<a name="map-command"></a>

`Aws\Middleware::mapCommand` 미들웨어는 명령을 HTTP 요청으로 직렬화하기 전에 명령을 수정해야 하는 경우에 유용합니다. 예를 들어, `mapCommand`는 기본 파라미터를 확인하거나 추가하는 데 사용할 수 있습니다. `mapCommand` 함수는 `Aws\CommandInterface` 객체를 받아 `Aws\CommandInterface` 객체를 반환하는 collable을 받습니다.

```
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
<a name="map-request"></a>

`Aws\Middleware::mapRequest` 미들웨어는 요청을 직렬화한 후 전송하기 이전에 수정해야 하는 경우에 유용합니다. 예를 들어, 요청에 사용자 지정 HTTP 헤더를 추가하는 데 사용할 수 있습니다. `mapRequest` 함수는 `Psr\Http\Message\RequestInterface` 인수를 받아 `Psr\Http\Message\RequestInterface` 객체를 반환하는 collable을 받습니다.

```
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
<a name="mapresult"></a>

`Aws\Middleware::mapResult` 미들웨어는 명령 실행 결과를 수정해야 하는 경우에 유용합니다. `mapResult` 함수는 `Aws\ResultInterface` 인수를 받야 `Aws\ResultInterface` 객체를 반환하는 collable을 받습니다.

```
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` 속성이 포함되어 있습니다.

#### 기록
<a name="history"></a>

`history` 미들웨어는 SDK에서 예상한 명령을 실행하고, 예상한 HTTP 요청을 전송하고, 예상한 결과를 수신했는지 테스트하는 데 유용합니다. 이 미들웨어는 웹 브라우저의 검색 기록과 비슷한 역할을 합니다.

```
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
<a name="tap"></a>

`tap` 미들웨어는 관찰자로 사용됩니다. 미들웨어의 체인을 통해 명령을 전송할 경우 이 미들웨어를 사용하여 함수를 호출할 수 있습니다. `tap` 함수는 `Aws\CommandInterface` 및 실행 중인 `Psr\Http\Message\RequestInterface`(옵션)를 받는 collable 함수입니다.

```
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";
        }
    }
);
```

## 사용자 지정 핸들러 생성
<a name="creating-custom-handlers"></a>

핸들러는 `Aws\CommandInterface` 객체와 `Psr\Http\Message\RequestInterface` 객체를 받아 `GuzzleHttp\Promise\PromiseInterface`와 함께 실행되거나 `Aws\ResultInterface`와 함께 거부되는 `Aws\Exception\AwsException`를 반환하는 단순한 함수입니다.

SDK에는 다양한 `@http` 옵션이 있지만 핸들러에서는 다음 옵션을 사용하는 방법만 알면 됩니다.
+  [connect\$1timeout](guide_configuration.md#http-connect-timeout) 
+  [debug](guide_configuration.md#http-debug) 
+  [decode\$1content](guide_configuration.md#http-decode-content)(선택 사항)
+  [delay](guide_configuration.md#http-delay) 
+  [progress](guide_configuration.md#http-progress)(선택 사항)
+  [proxy](guide_configuration.md#http-proxy) 
+  [sink](guide_configuration.md#http-sink) 
+  [synchronous](guide_configuration.md#http-sync)(선택 사항)
+  [stream](guide_configuration.md#http-stream)(선택 사항)
+  [제한 시간](guide_configuration.md#http-timeout) 
+  [verify](guide_configuration.md#http-verify) 
+ http\$1stats\$1receiver(선택 사항) - [stats](guide_configuration.md#config-stats) 구성 파라미터를 사용하여 요청된 경우 HTTP 전송 통계의 연결 배열을 사용하여 호출하는 함수

이 옵션을 선택 사항으로 지정한 경우 핸들러는 옵션을 처리하거나 거부된 promise를 반환할 수 있어야 합니다.

특정 `@http` 옵션 처리 외에도 핸들러는 다음과 같은 형식의 `User-Agent` 헤더를 추가해야 합니다. 여기서 “3.X”를 `Aws\Sdk::VERSION`으로 바꿀 수 있고 “HandlerSpecificData/version ...”을 사용 중인 핸들러별 User-Agent 문자열로 바꾸어야 합니다.

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