

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# HTTP 拦截器
<a name="interceptors"></a>

 您可以使用拦截器介入 API 请求和响应的执行过程。拦截器是一种开放式机制，在这种机制中，SDK 会调用您编写的代码，以将行为注入到请求/响应生命周期中。这样，您便可修改正在进行的请求、调试请求处理、查看异常等。

## 拦截器与中间件
<a name="interceptors-vs-middleware"></a>

 适用于 Go 的 AWS SDK v2 提供了拦截器和中间件，用于自定义请求处理。虽然两者的作用相似，但它们针对的受众和应用场景却有所不同：
+  **拦截器**专为想要使用简单的、以 HTTP 为中心的 API 对请求/响应处理进行自定义的 SDK 用户而设计。它们在请求生命周期中提供特定的钩子点，并直接处理 HTTP 请求和响应。
+  **中间件**是一种更为高级且与传输方式无关的系统，主要由 SDK 在内部使用。虽然中间件功能强大，但需要更深入地了解 SDK 内部结构，并且涉及更复杂的接口。

 在常见使用案例中，拦截器相较于中间件的主要优势如下：
+  **以 HTTP 为中心**：拦截器直接处理 HTTP 请求和响应，无需像中间件那样进行传输类型检查。
+  **更简单的接口**：每个拦截器钩子都有一个特定的、有针对性的接口，而不是通用的中间件模式。
+  **更清晰的执行模型**：拦截器在请求生命周期中定义明确的时刻执行，无需了解中间件堆栈排序。

**注意**  
 拦截器在现有的中间件系统上构建而成，因此两者可以在同一个应用程序中共存。中间件仍可用于需要与传输无关的行为或复杂堆栈操作的高级使用案例。

## 可用拦截器钩子
<a name="interceptor-hooks"></a>

 适用于 Go 的 AWS SDK v2 在请求生命周期的各个阶段都提供拦截器钩子。每个钩子都对应一个您可以实现的特定接口：
+  `BeforeExecution` - 操作执行期间调用的第一个钩子 
+  `BeforeSerialization` - 在输入消息序列化为传输请求之前 
+  `AfterSerialization` - 在输入消息序列化为传输请求之后 
+  `BeforeRetryLoop` - 在进入重试循环之前 
+  `BeforeAttempt` - 重试循环内调用的第一个钩子 
+  `BeforeSigning` - 在签署运输请求之前 
+  `AfterSigning` - 在签署运输请求之后 
+  `BeforeTransmit` - 在发送传输请求之前 
+  `AfterTransmit` - 在收到运输响应之后 
+  `BeforeDeserialization` - 在传输响应被反序列化之前 
+  `AfterDeserialization` - 在解组传输响应之后 
+  `AfterAttempt` - 重试循环内调用的最后一个钩子 
+  `AfterExecution` - 操作执行期间调用的最后一个钩子 

 您可以在单个拦截器中实现多个接口，以介入请求生命周期的多个阶段。

## 拦截器注册
<a name="interceptor-registration"></a>

 构造服务客户端或覆盖特定操作的配置时，可以注册拦截器。注册方式会有所不同，具体取决于您希望拦截器应用于客户端的所有操作，还是仅应用于特定操作。

 通过拦截器注册表来管理拦截器，该注册表提供了添加和删除拦截器的方法。以下示例显示了一个简单的拦截器，该拦截器在签名过程之前向传出的请求添加 AWS X-Ray 跟踪 ID 标头：

```
type recursionDetection struct{}

func (recursionDetection) BeforeSigning(ctx context.Context, in *smithyhttp.InterceptorContext) error {
    if traceID := os.Getenv("_X_AMZN_TRACE_ID"); traceID != "" {
        in.Request.Header.Set("X-Amzn-Trace-Id", traceID)
    }
    return nil
}

// use it on the client
svc := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.Interceptors.AddBeforeSigning(recursionDetection{})
})
```

 拦截器注册表已添加到客户端选项中，从而能够按操作来配置拦截器：

```
// ... or use it per-operation
s3.ListBuckets(context.Background(), &s3.ListBucketsInput{
}, func(o *s3.Options) {
   o.Interceptors.AddBeforeSigning(recursionDetection{})
})
```

## 全局拦截器配置
<a name="interceptor-global-config"></a>

 您还可以使用 `config.LoadDefaultConfig` 函数在全局注册拦截器，每种拦截器类型都有相应的 `With*` 选项。这会将拦截器应用于根据该配置创建的所有 AWS 服务客户端：

```
type myExecutionInterceptor struct{}

func (*myExecutionInterceptor) AfterExecution(ctx context.Context, in *smithyhttp.InterceptorContext) error {
    // Add your custom logic here
    return nil
}

cfg, err := config.LoadDefaultConfig(context.Background(),
    config.WithAfterExecution(&myExecutionInterceptor{}))
if err != nil {
    panic(err)
}

// every service client created from the above config
// will include this interceptor
svc := s3.NewFromConfig(cfg)
```