

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

# 在适用于 Rust 的 AWS SDK 中配置服务客户端
<a name="configure"></a>

 要以编程方式访问 AWS 服务，适用于 Rust 的 AWS SDK 对每个 AWS 服务使用一个客户端结构体。例如，如果您的应用程序需要访问 Amazon EC2，则您的应用程序会创建一个 Amazon EC2 客户端结构体来与该服务交互。然后，您可以使用服务客户端向该 AWS 服务 发出请求。

要向 AWS 服务发出请求，您必须先创建和配置服务客户端。对于您的代码使用的每个 AWS 服务，它都有自己的 crate 和用于与之交互的专用类型。客户端为服务公开的每个 API 操作公开一种方法。

配置 SDK 行为的方法有很多，但归根结底，一切都与服务客户端的行为有关。除非使用基于配置创建的服务客户端，否则任何配置都不会生效。

在使用 AWS 服务进行开发时，您必须确定您的代码是如何使用 AWS 进行身份验证的。您还必须设置要使用的 AWS 区域。

[AWS SDK 和工具参考指南](https://docs.aws.amazon.com/sdkref/latest/guide/)还介绍了在许多 AWS SDK 中常见的设置、功能和其他基础概念。

**Topics**
+ [在外部配置客户端](config-external.md)
+ [代码中的客户端配置](config-code.md)
+ [AWS 区域](region.md)
+ [凭证提供程序](credproviders.md)
+ [行为版本](behavior-versions.md)
+ [重试](retries.md)
+ [超时](timeouts.md)
+ [可观测性](observability.md)
+ [客户端端点](endpoints.md)
+ [覆盖操作配置](peroperation.md)
+ [HTTP](http.md)
+ [拦截器](interceptors.md)

# 在外部配置适用于 Rust 的 AWS SDK 服务客户端
<a name="config-external"></a>

许多配置设置可以通过代码以外的方式来处理。在外部处理配置时，配置将应用于您的所有应用程序。大多数配置设置可以设置为环境变量，也可以在单独的共享 AWS `config` 文件中设置。共享 `config` 文件可以维护多组独立的设置（称为配置文件），以便为不同的环境或测试提供不同的配置。

环境变量和共享 `config` 文件设置都已标准化，可在 AWS SDK 和工具之间共享，从而支持在不同编程语言和应用程序之间保持一致的功能。

请参阅《AWS SDK 和工具参考指南》**，了解如何通过这些方法配置应用程序，以及每个跨 SDK 设置的详细信息。要查看 SDK 可以从环境变量或配置文件中解析的所有设置，请参阅《AWS SDK 和工具参考指南》**中的[设置参考](https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html)。

要向 AWS 服务发出请求，请先实例化该服务对应的客户端。您可以为服务客户端配置常用设置，例如超时、HTTP 客户端及重试配置。

每个服务客户端都需要一个 AWS 区域和一个凭证提供程序。SDK 使用这些值将您的资源请求发送到正确的区域，并使用正确的凭证对请求进行签名。您可以在代码中以编程方式指定这些值，也可以让它们从环境变量中自动加载。

该 SDK 有一系列地点（或来源），它会检查这些地点（或来源），以便找到配置设置的值。

1. 在代码中或服务客户端本身上设置的任何显式设置均优先于其他任何设置。

1. 环境变量
   + 有关设置环境变量的详细信息，请参阅《AWS SDK 和工具参考指南》**中的[环境变量](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html)。
   + 请注意，您可以在不同作用域层级为 shell 配置环境变量：系统级、用户级，以及特定终端会话级。

1. 共享`config`文件和`credentials`文件
   + 有关设置这些文件的详细信息，请参阅《AWS SDK 和工具参考指南》**中的[共享 `config` 和 `credentials` 文件](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html)。

1. 最后才会使用 SDK 源代码本身提供的任何默认值。
   + 某些属性（例如“区域”）没有默认值。您必须在代码、环境设置或共享 `config` 文件中明确指定这些属性。如果 SDK 无法解析所需的配置，API 请求在运行时会失败。

# 在代码中为 Rust 服务客户端配置 AWS SDK
<a name="config-code"></a>

当直接在代码中处理配置时，配置范围仅限于使用该代码的应用程序。在该应用程序中，您可选择以下配置方式：对所有服务客户端的全局配置、对某一特定 AWS 服务 类型所有客户端的配置，或对某个具体服务客户端实例的配置。

要向发出请求 AWS 服务，请先为该服务实例化客户端。您可以为服务客户端配置常用设置，例如超时、HTTP 客户端及重试配置。

每个服务客户端都需要一个 AWS 区域 和一个凭据提供商。SDK 使用这些值将您的资源请求发送到正确的区域，并使用正确的凭证对请求进行签名。您可以在代码中以编程方式指定这些值，也可以让它们从环境变量中自动加载。

**注意**  
服务客户端的构造成本可能很高，而且通常需要共享。为了便于实现这一点，所有 `Client` 结构体均实施 `Clone`。

## 从环境中配置客户端
<a name="configure-a-client-from-the-environment"></a>

要创建具有环境源配置的客户端，请使用 `aws-config` crate 中的静态方法：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);
```

在 Amazon Elastic Compute Cloud 上运行时 AWS Lambda，或者在任何其他可以直接从环境中配置服务客户端的环境中运行时，以这种方式创建客户端非常有用。这样可以将您的代码与其运行的环境分离，并且可以更轻松地将您的应用程序部署到多个环境中， AWS 区域 而无需更改代码。

您可以显式覆盖特定属性。显式配置优先于从执行环境中解析的配置。以下示例从环境加载配置，但显式覆盖 AWS 区域：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .region("us-east-1")
    .load()
    .await;
    
let s3 = aws_sdk_s3::Client::new(&config);
```

**注意**  
并非所有配置值都是在创建时由客户端提供的。当使用客户端发出请求时，凭证提供程序层会访问与凭证相关的设置，例如临时访问密钥和 IAM Identity Center 配置。

前面示例中显示的代码 `BehaviorVersion::latest()` 指出了默认使用的 SDK 版本。`BehaviorVersion::latest()` 适用于大多数情况。有关更多信息，请参阅 [在中使用行为版本 适用于 Rust 的 AWS SDK](behavior-versions.md)。

## 使用生成器模式进行特定于服务的设置
<a name="configure-a-client-builder"></a>

有些选项只能在特定的服务客户端类型上配置。但是，大多数情况下，您仍然需要从环境中加载大部分配置，然后专门添加其他选项。建造者模式是 适用于 Rust 的 AWS SDK 箱子里常见的模式。您首先使用 `aws_config::defaults` 加载常规配置，然后使用 `from` 方法将该配置加载到您正在使用的服务的生成器中。然后，您可以为该服务设置任何唯一的配置值并调用 `build`。最后，根据此修改后的配置创建客户端。

```
// Call a static method on aws-config that sources default config values.
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

// Use the Builder for S3 to create service-specific config from the default config.
let s3_config = aws_sdk_s3::config::Builder::from(&config)
    .accelerate(true) // Set an S3-only configuration option
    .build();

// Create the client.
let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

要发现特定类型服务客户端可用的其他方法，一种方法是使用 API 文档，例如 [https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/struct.Builder.html](https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/struct.Builder.html) 的文档。

## 高级显式客户端配置
<a name="configure-a-client-explicitly"></a>

要使用特定值配置服务客户端，而不是从环境中加载配置，您可以在客户端 `Config` 生成器上指定这些值，如下所示：

```
let conf = aws_sdk_s3::Config::builder()
    .region("us-east-1")
    .endpoint_resolver(my_endpoint_resolver)
    .build();

let s3 = aws_sdk_s3::Client::from_conf(conf);
```

使用 `aws_sdk_s3::Config::builder()` 创建服务配置时，*不会加载任何默认配置*。只有在基于 `aws_config::defaults` 创建配置时才会加载默认配置。

有些选项只能在特定的服务客户端类型上配置。前面的示例显示了如何在 Amazon S3 客户端上使用 `endpoint_resolver` 函数来实现这一点。

# AWS 区域 为 适用于 Rust 的 AWS SDK
<a name="region"></a>

您可以使用访问 AWS 服务 在特定地理区域运营的内容 AWS 区域。它可以用于保证冗余，并保证您的数据和应用程序接近您和用户访问它们的位置。有关如何使用区域的更多信息，请参阅*AWS SDKs 和工具参考指南[AWS 区域](https://docs.aws.amazon.com/sdkref/latest/guide/feature-region.html)*中的。

**重要**  
大多数资源都位于特定的区域 AWS 区域 ，在使用 SDK 时，您必须为该资源提供正确的区域。

你必须为 Rust AWS 区域 的 SDK 设置默认值才能用于 AWS 请求。此默认设置用于未指定区域的任何 SDK 服务方法调用。

有关如何通过共享 AWS `config`文件或环境变量设置默认区域的示例，请参阅*AWS SDKs 和工具参考指南[AWS 区域](https://docs.aws.amazon.com/sdkref/latest/guide/feature-region.html)*中的。

## AWS 区域 提供者链
<a name="region-provider-chain"></a>

 从执行环境加载服务客户端的配置时，将使用以下查找过程。SDK 找到的第一个已设置的值将用于客户端配置。有关创建服务客户端的更多信息，请参阅[从环境中配置客户端](config-code.md#configure-a-client-from-the-environment)。

1. 以编程方式设置显式区域。

1. 系统会检查 `AWS_REGION` 环境变量。
   + 如果您正在使用该 AWS Lambda 服务，则此环境变量由 AWS Lambda 容器自动设置。

1. 已选中共享 AWS `config`文件中的`region`属性。
   + `AWS_CONFIG_FILE` 环境变量可用于更改共享 `config` 文件的位置。要详细了解此文件的保存[位置，请参阅《工具参考指南》`config`和《工具参考指南》中的共享`credentials`文件AWS](https://docs.aws.amazon.com/sdkref/latest/guide/file-location.html)*SDKs 和*文件的位置。
   + `AWS_PROFILE` 环境变量可用于选择命名配置文件而不是默认配置文件。要了解有关配置不同配置文件的更多信息，请参阅[`config`和*工具参考指南中的共享AWS SDKs 和`credentials`*文件](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html)。

1. SDK 将尝试使用 Amazon EC2 实例元数据服务，为当前运行的 Amazon EC2 实例确定区域。
   +  适用于 Rust 的 AWS SDK 唯一的支持 IMDSv2。

在创建与服务客户端一起使用的基本配置时，系统会自动使用 `RegionProviderChain`，无需额外的代码：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;
```

## 设置输入 AWS 区域 代码
<a name="RegionProgram"></a>

### 在代码中显式设置区域
<a name="RegionNew"></a>

如果要显式设置区域，请直接在配置中使用 `Region::new()`。

未使用区域提供程序链，不检查环境、共享 `config` 文件或 Amazon EC2 实例元数据服务。

```
use aws_config::{defaults, BehaviorVersion};
use aws_sdk_s3::config::Region;

#[tokio::main]
async fn main() {
    let config = defaults(BehaviorVersion::latest())
        .region(Region::new("us-west-2"))
        .load()
        .await;

    println!("Using Region: {}", config.region().unwrap());
}
```

请务必为输入有效的字符串 AWS 区域；所提供的值未经过验证。

### 自定义 `RegionProviderChain`
<a name="regionProviderChain"></a>

如果您想有条件地注入区域、覆盖它或自定义解析链，请使用[AWS 区域 提供者链](#region-provider-chain)。

```
use aws_config::{defaults, BehaviorVersion};
use aws_config::meta::region::RegionProviderChain;
use aws_sdk_s3::config::Region;
use std::env;

#[tokio::main]
async fn main() {  
    let region_provider = RegionProviderChain::first_try(env::var("CUSTOM_REGION").ok().map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-east-2"));
    
    let config = aws_config::defaults(BehaviorVersion::latest())
        .region(region_provider)
        .load()
        .await;

    println!("Using Region: {}", config.region().unwrap());
}
```

 之前的配置将：

1. 首先检查 `CUSTOM_REGION` 环境变量中是否设置了字符串。

1. 如果不可用，请回退到默认的区域提供程序链。

1. 如果失败了，请使用“us-east-2”作为最终回退选项。

# 使用 AWS 适用于 Rust 凭证提供商的 SDK
<a name="credproviders"></a>

 对的所有请求都 AWS 必须使用颁发的凭证进行加密签名。 AWS运行时，SDK 会通过检查多个位置来获取凭证的配置值。

如果检索到的配置包含 [AWS IAM Identity Center 单点登录访问设置](credentials.md)，则 SDK 将与 IAM Identity Center 配合检索用于向 AWS 服务发出请求的临时凭证。

如果检索到的配置包含[临时证书](https://docs.aws.amazon.com/sdkref/latest/guide/access-temp-idc.html)，SDK 将使用它们进行 AWS 服务 调用。临时凭证由访问密钥对和会话令牌组成。

身份验证 AWS 可以在您的代码库之外处理。SDK 可通过凭证提供程序链自动检测、使用并刷新多种身份验证方式。

有关项目 AWS 身份验证入门的指导选项，请参阅[和*工具参考指南中的身份验证AWS SDKs 和*访问权限](https://docs.aws.amazon.com/sdkref/latest/guide/access.html)。

## 凭证提供程序链
<a name="credproviders-default-credentials-provider-chain"></a>

如果您在构建客户端时没有显式指定凭证提供程序，那么适用于 Rust 的 SDK 会使用凭证提供程序链来检查一系列可以提供凭证的位置。SDK 在其中一个位置找到凭证后，搜索就会停止。有关构建客户端的详细信息，请参阅[在代码中为 Rust 服务客户端配置 AWS SDK](config-code.md)。

以下示例未在代码中指定凭证提供程序。SDK 使用凭证提供程序链来检测在托管环境中设置的身份验证，并将该身份验证用于 AWS 服务调用。

```
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let s3 = aws_sdk_s3::Client::new(&config);
```

### 凭证检索顺序
<a name="credproviders-credential-retrieval-order"></a>

凭证提供程序链使用以下预定义序列搜索凭证：

1. **访问密钥环境变量**

   SDK 尝试从 `AWS_ACCESS_KEY_ID` 和 `AWS_SECRET_ACCESS_KEY` 以及 `AWS_SESSION_TOKEN` 环境变量加载凭证。

1. **共享的 AWS `config`和`credentials`文件**

   SDK 尝试从共享 AWS `config`和`credentials`文件中的`[default]`配置文件加载凭证。您可以使用 `AWS_PROFILE` 环境变量来选择您想让 SDK 加载的命名配置文件，而不是使用 `[default]`。`config`和`credentials`文件由各种 AWS SDKs 工具共享。有关这些文件的更多信息，请参阅[`config`和*工具参考指南中的共享AWS SDKs 和`credentials`*文件](https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html)。有关可在配置文件中指定的标准化提供商的更多信息，请参阅[AWS SDKs 和工具标准化凭证提供商](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html)。

1. **AWS STS 网络身份**

   在创建需要访问的移动应用程序或基于客户端的 Web 应用程序时 AWS， AWS Security Token Service (AWS STS) 会为通过公共身份提供商 (IdP) 进行身份验证的联合用户返回一组临时安全证书。
   + 当您在配置文件中指定此项时，SDK 或工具会尝试使用 AWS STS `AssumeRoleWithWebIdentity` API 方法检索临时证书。有关此方法的详细信息，请参阅 *AWS Security Token Service API 参考[AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)*中的。
   +  有关配置此提供程序的指导，请参阅《*和工具参考指南》AWS SDKs 中的* “[使用网络身份进行联合” 或 OpenID](https://docs.aws.amazon.com/sdkref/latest/guide/access-assume-role.html#webidentity) Connect。
   +  有关此提供商的 SDK 配置属性的详细信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考指南*》中的代入[角色凭据提供程序](https://docs.aws.amazon.com/sdkref/latest/guide/feature-assume-role-credentials.html)。

1. **Amazon ECS 和 Amazon EKS 容器凭证**

   您的 Amazon Elastic Container Service 任务和 Kubernetes 服务账户可以具有与其关联的 IAM 角色。在 IAM 角色中授予的权限由任务中运行的容器或容器组（Pod）内的容器承担。此角色允许适用于 Rust 的 SDK 应用程序代码（在容器上）使用其他 AWS 服务。

   SDK 尝试从 `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` 或 `AWS_CONTAINER_CREDENTIALS_FULL_URI` 环境变量检索凭证，这些变量可以由 Amazon ECS 和 Amazon EKS 自动设置。
   + 有关为 Amazon ECS 设置此角色的详细信息，请参阅《Amazon Elastic Container Service 开发人员指南》**中的 [Amazon ECS 任务 IAM 角色](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html)。
   + 有关 Amazon EKS 的设置信息，请参阅《Amazon EKS 用户指南》****中的[设置 Amazon EKS 容器组身份代理](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-agent-setup.html)。
   +  有关此提供商的 SDK 配置属性的详细信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考指南*》中的[容器凭证提供程序](https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html)。

1. **Amazon EC2 实例元数据服务**

   创建 IAM 角色并将其附加到您的实例。实例上适用于 Rust 的 SDK 应用程序会尝试从实例元数据中检索由角色提供的凭证。
   + 适用于 Rust 的软件开发工具包仅支持[IMDSv2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html)。
   + 有关设置此角色和使用元数据的详细信息，请参阅《Amazon EC2 用户指南》**中的 [Amazon EC2 的 IAM 角色](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)和[使用实例元数据](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)。
   +  有关此提供商的 SDK 配置属性的详细信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考*指南》中的 [IMDS 凭证提供程序](https://docs.aws.amazon.com/sdkref/latest/guide/feature-imds-credentials.html)。

1. 如果此时仍未解析凭证，则操作 panics 会出现错误。

有关 AWS 凭据提供程序配置设置的详细信息，请参阅《*工具*参考指南》的 *“设置” 参考*中的[标准化凭据提供程序](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html)。AWS SDKs 

## 显式凭证提供程序
<a name="credproviders-explicit-credentials-provider"></a>

您可以指定 SDK 应使用的特定凭证提供程序，而不是依赖凭证提供程序链来检测您的身份验证方法。使用 `aws_config::defaults` 加载常规配置时，您可以指定自定义凭证提供程序，如下所示：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .credentials_provider(MyCredentialsProvider::new())
    .load()
    .await;
```

您可以通过实现 [https://docs.rs/aws-credential-types/latest/aws_credential_types/provider/trait.ProvideCredentials.html](https://docs.rs/aws-credential-types/latest/aws_credential_types/provider/trait.ProvideCredentials.html) 特性来实施自己的凭证提供程序。

## 身份缓存
<a name="credproviders-identity-caching"></a>

SDK 将缓存凭证和其他身份类型，例如 SSO 令牌。默认情况下，SDK 使用惰性缓存实现：在首次请求时加载凭证并缓存，当凭证即将过期时，会在下次请求时尝试刷新。从同一个 `SdkConfig` 创建的客户端共享一个 [https://docs.rs/aws-smithy-runtime/latest/aws_smithy_runtime/client/identity/struct.IdentityCache.html](https://docs.rs/aws-smithy-runtime/latest/aws_smithy_runtime/client/identity/struct.IdentityCache.html)。

# 在中使用行为版本 适用于 Rust 的 AWS SDK
<a name="behavior-versions"></a>

适用于 Rust 的 AWS SDK 开发人员期望并依赖该语言及其主要库提供的强大且可预测的行为。为了帮助使用适用于 Rust 的 SDK 的开发人员获得预期行为，客户端配置需要包含 `BehaviorVersion`。`BehaviorVersion` 指定预期为默认值的 SDK 版本。这使得 SDK 可以不断发展，改变最佳实践以匹配新标准并支持新功能，而不会对应用程序的行为产生意想不到的不利影响。

**警告**  
如果您尝试配置 SDK 或创建客户端，但未明确指定 `BehaviorVersion`，则构造函数会 panic。

例如，假设发布了新版本的 SDK，并采用了新的默认重试策略。如果您的应用程序使用与先前版本的 SDK 匹配的 `BehaviorVersion`，则将使用该先前配置而不是新的默认配置。

每次发布适用于 Rust 的 SDK 的新行为版本时，之前的 `BehaviorVersion` 都会被标记为适用于 Rust 的 SDK `deprecated` 属性，并且会添加新版本。这会导致在编译时出现警告，但除此之外，构建过程会照常进行。`BehaviorVersion::latest()` 也会更新，以指示新版本的默认行为。

**注意**  
如果您的代码不依赖于极其具体的行为特性，则应在代码中使用 `BehaviorVersion::latest()`，或者在 `Cargo.toml` 文件中使用功能标志 `behavior-version-latest`。如果您要编写对延迟敏感的代码或用于调整 Rust SDK 行为的代码，可以考虑将 `BehaviorVersion` 固定到特定的主要版本。

## 在 `Cargo.toml` 中设置行为版本
<a name="set-the-behavior-version-in-cargo-toml"></a>

您可以通过在 `Cargo.toml` 文件中添加相应的功能标志，为 SDK 和各个模块（例如 `aws-sdk-s3` 或 `aws-sdk-iam`）指定行为版本。目前，`Cargo.toml` 仅支持 `latest` 版本的 SDK。

```
[dependencies]
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-sdk-s3 = { version = "1", features = ["behavior-version-latest"] }
```

## 在代码中设置行为版本
<a name="set-the-behavior-version-in-code"></a>

您可以通过在配置 SDK 或客户端时指定行为版本，根据需要更改代码的行为版本：

```
let config = aws_config::load_defaults(BehaviorVersion::v2023_11_09()).await;
```

此示例创建了一个配置，该配置使用环境来配置 SDK，但将 `BehaviorVersion` 设置为 `v2023_11_09()`。

# 在 Rust AWS 开发工具包中配置重试次数
<a name="retries"></a>

适用于 Rust 的 AWS SDK 为服务请求提供了默认的重试行为和可自定义的配置选项。调用 AWS 服务 偶尔会返回意外异常。如果重试调用，某些类型的错误（例如节流或暂时错误）可能会成功。

重试行为可以使用共享 AWS `config`文件中的环境变量或设置进行全局配置。有关此方法的信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考指南*》中的[重试行为](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html)。它还包括有关重试策略实现以及如何选择一种策略而不是另一种策略的详细信息。

或者，您也可以在代码中配置这些选项，如以下部分所示。

## 默认重试配置
<a name="defaultRetryConfig"></a>

 每个服务客户端都默认使用通过 [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) 结构提供的 `standard` 重试策略配置。默认情况下，一个调用将尝试三次（*初次尝试加上两次重试*）。此外，为了避免重试风暴，每次重试都将随机延迟一小段时间。此约定适用于大多数使用案例，但可能不适用于特定情况，例如高吞吐量系统。

 只有某些类型的错误被认为是可重试的。 SDKs可重试错误示例如下：
+ 套接字超时
+ 服务端节流
+ 暂时性服务错误，例如 HTTP 5XX 响应

以下示例**不属于**可重试范畴：
+ 参数缺失或无效
+ 身份验证/安全错误
+ 配置错误异常

您可以通过设置最大尝试次数、延迟和回退配置来自定义 `standard` 重试策略。

## 最大尝试次数
<a name="maxAttempts"></a>

您可以通过向 `aws_config::defaults` 提供修改后的 [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) 来自定义代码中的最大尝试次数：

```
const CUSTOM_MAX_ATTEMPTS: u32 = 5;
let retry_config = RetryConfig::standard()
    // Set max attempts. When max_attempts is 1, there are no retries.
    // This value MUST be greater than zero.
    // Defaults to 3.
    .with_max_attempts(CUSTOM_MAX_ATTEMPTS);
  
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(retry_config)
    .load()
    .await;
```

## 延迟和回退
<a name="delays"></a>

如果需要重试，默认的重试策略会在进行下一次尝试之前等待一段时间。第一次重试的延迟时间很短，但后续重试的延迟时间会呈指数级增长。最长延迟时间是有上限的，以防延迟时间过长。

系统会将随机抖动应用于所有尝试之间的延迟。抖动有助于降低可能导致重试风暴的大量重试的影响。有关指数回退和抖动的更深入讨论，请参阅 *AWS 架构博客*中的[指数回退和抖动](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)。

 您可以通过向 `aws_config::defaults` 提供修改后的 [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) 来自定义代码中的延迟设置。以下代码将延迟配置设置为第一次重试尝试最多延迟 100 毫秒，并且任何重试尝试之间的最大时间间隔为 5 秒。

```
let retry_config = RetryConfig::standard()
    // Defaults to 1 second.
    .with_initial_backoff(Duration::from_millis(100))
    // Defaults to 20 seconds.
    .with_max_backoff(Duration::from_secs(5));
  
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(retry_config)
    .load() 
    .await;
```

## 自适应重试模式
<a name="AdaptiveRetryMode"></a>

 作为 `standard` 模式重试策略的替代方案，`adaptive` 模式重试策略是一种高级方法，旨在寻找理想的请求速率以尽可能减少节流错误。

**注意**  
自适应重试是一种高级重试模式。通常不建议使用此策略。请参阅《工具参考指南》*AWS SDKs 和《工具参考指南》*中的[重试行为](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html#standardvsadaptive)。

自适应重试具备标准重试的所有功能。它添加了一个客户端速率限制器，用于衡量节流请求与非节流请求的比率。它还会限制尝试流量以保持在安全带宽内，理想情况下会使节流错误为零。

该速率会根据不断变化的服务条件和流量模式实时调整，并可能相应地增加或减少流量速率。至关重要的是，在高流量场景中，速率限制器可能会延迟初始尝试。

您可以通过提供修改后的 [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) 来选择代码中的 `adaptive` 重试策略：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(RetryConfig::adaptive())
    .load()
    .await;
```

# 在 Rust AWS 开发工具包中配置超时
<a name="timeouts"></a>

适用于 Rust 的 AWS SDK 提供了多种用于管理 AWS 服务 请求超时和停滞数据流的设置。当网络中发生意外延迟和故障时，这些设置可以帮助应用程序以最佳状态运行。

## API 超时
<a name="api-timeouts"></a>

当存在可能导致请求尝试花费很长时间或完全失败的暂时性问题时，请务必检查和设置超时，这样应用程序才能实施快速失效机制并以最佳状态运行。SDK 可以自动重试失败的请求。为单个尝试和整个请求都设置超时是一种很好的做法。

适用于 Rust 的 SDK 提供了为请求建立连接的默认超时。SDK 没有为接收请求尝试或整个请求的响应设置任何默认最大等待时间。以下超时选项可用：


| 参数 | 默认 值 | 说明 | 
| --- | --- | --- | 
| 连接超时 | 3.1 秒 | 放弃连接前等待建立连接的最长时间。 | 
| 操作超时 | 无 | 接收来自适用于 Rust 的 SDK 的响应之前要等待的最长时间，包括所有重试。 | 
| 操作尝试超时 | 无 | 等待单次 HTTP 尝试的最长时间，超过该时长之后可以重试 API 调用。 | 
| 读取超时 | 无 | 自请求发起到读取响应的第一个字节的最长时间。 | 

以下示例演示了使用自定义超时值配置 Amazon S3 客户端的过程。

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .timeout_config(
        TimeoutConfig::builder()
            .operation_timeout(Duration::from_secs(5))
            .operation_attempt_timeout(Duration::from_millis(1500))
            .build()
    )
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);
```

将这些操作和尝试超时一起使用时，可以对所有重试尝试所花费的总时间设置硬性限制。您还可以将单个 HTTP 请求设置为在慢速请求时快速失败。

除了在服务客户端上为所有操作设置这些超时值之外，您还可以[为单个请求配置或覆盖这些超时值](peroperation.md)。

**重要**  
对于在适用于 Rust 的 SDK 返回响应后使用的流数据，操作和尝试超时不适用。例如，使用来自响应 `ByteStream` 成员的数据不受操作超时的影响。

## 停滞流保护
<a name="stalled-stream-protection"></a>

适用于 Rust 的 SDK 提供了另一种与检测停滞流相关的超时机制。停滞流是指在超过配置的宽限期后仍未生成任何数据的上传或下载流。这有助于防止应用程序无限期挂起而永远无法取得进展。

 停滞流保护会在流空闲时间超过可接受时段时返回错误。

默认情况下，适用于 Rust 的 SDK 为上传和下载启用停滞的直播保护，并在 20 秒 byte/sec 的宽限期内查找至少 1 个活动。

以下示例展示了禁用上传保护并将无活动宽限期更改为 10 秒的自定义 `StalledStreamProtectionConfig`：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .stalled_stream_protection(
        StalledStreamProtectionConfig::enabled()
            .upload_enabled(false)
            .grace_period(Duration::from_secs(10))
            .build()
    )
    .load()
    .await;
```

**警告**  
停滞流保护是一个高级配置选项。建议仅在应用程序对性能要求更高或这些值会导致一些其他问题时才更改这些值。

### 禁用停滞流保护
<a name="disable-stalled-stream-protection"></a>

以下示例展示了如何完全禁用停滞流保护：

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .stalled_stream_protection(StalledStreamProtectionConfig::disabled())
    .load()
    .await;
```

# 在适用于 Rust 的 AWS SDK 中配置可观测性功能
<a name="observability"></a>

 可观测性是指可以根据系统发出的数据推断出其当前状态的程度。发出的数据通常称为遥测。

**Topics**
+ [日志记录](logging.md)

# 在适用于 Rust 的 AWS SDK 中配置和使用日志记录
<a name="logging"></a>

适用于 Rust 的 AWS SDK 使用[跟踪](http://tracing.rs/)框架进行日志记录。要启用日志记录，请添加 `tracing-subscriber` crate 并在 Rust 应用程序中对其进行初始化。日志包括时间戳、日志级别和模块路径，有助于调试 API 请求和 SDK 行为。使用 `RUST_LOG` 环境变量控制日志的详细程度，必要时按模块筛选。

## 如何在适用于 Rust 的 AWS SDK 中启用日志记录
<a name="enableLogging"></a>

1. 在项目目录的命令提示符中，将 [tracing-subscriber](https://crates.io/crates/tracing-subscriber) crate 添加为依赖项：

   ```
   $ cargo add tracing-subscriber --features tracing-subscriber/env-filter
   ```

   这会将 crate 添加到 `Cargo.toml` 文件的 `[dependencies]` 部分。

1. 初始化订阅用户。通常，这是在调用任何适用于 Rust 的 SDK 操作之前在 `main` 函数中提早完成的：

   ```
   use aws_config::BehaviorVersion;
   
   type BoxError = Box<dyn Error + Send + Sync>;
   
   #[tokio::main]
   async fn main() -> Result<(), BoxError> {
       tracing_subscriber::fmt::init();  // Initialize the subscriber.
       
       let config = aws_config::defaults(BehaviorVersion::latest())
           .load()
           .await;
   
       let s3 = aws_sdk_s3::Client::new(&config);
   
       let _resp = s3.list_buckets()
           .send()
           .await?;
   
       Ok(())               
   }
   ```

1. 使用 `RUST_LOG` 环境变量启用日志记录。要启用日志记录信息的显示，请在命令提示符中将 `RUST_LOG` 环境变量设置为要记录的级别。以下示例将日志记录设置为 `debug` 级别。

------
#### [ Linux/macOS ]

   ```
   $ RUST_LOG=debug
   ```

------
#### [ Windows ]

   如果您使用的是 VSCode，则终端窗口通常默认为 PowerShell。验证您使用的提示类型。

   ```
   C:\> set RUST_LOG=debug
   ```

------
#### [ PowerShell ]

   ```
   PS C:\> $ENV:RUST_LOG="debug"
   ```

------

1. 运行程序：

   ```
   $ cargo run
   ```

   您应该在控制台或终端窗口中看到其他输出。

有关更多信息，请参阅 `tracing-subscriber` 文档中的[使用环境变量筛选事件](https://docs.rs/tracing-subscriber/0.3.18/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables)。

## 解读日志输出
<a name="logging-understanding"></a>

按照上一节中的步骤启用日志记录后，默认情况下，其他日志信息将打印为标准输出。

如果您使用的是默认日志输出格式（跟踪模块称之为“完整”），则您在日志输出中看到的信息类似于以下内容：

```
2024-06-25T16:10:12.367482Z DEBUG invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt:lazy_load_identity: aws_smithy_runtime::client::identity::cache::lazy: identity cache miss occurred; added new identity (took 480.892ms) new_expiration=2024-06-25T23:07:59Z valid_for=25066.632521s partition=IdentityCachePartition(7)
2024-06-25T16:10:12.367602Z DEBUG invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::identity::cache::lazy: loaded identity
2024-06-25T16:10:12.367643Z TRACE invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::orchestrator::auth: resolved identity identity=Identity { data: Credentials {... }, expiration: Some(SystemTime { tv_sec: 1719356879, tv_nsec: 0 }) }
2024-06-25T16:10:12.367695Z TRACE invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::orchestrator::auth: signing request
```

每个条目都包含以下值：
+ 日志条目的时间戳。
+ 条目的日志级别。这是一个单词，例如 `INFO`、`DEBUG` 或 `TRACE`。
+ 生成日志条目的嵌套[跨度](https://docs.rs/tracing/latest/tracing/span/index.html)集，用冒号(“:”)分隔。这可帮助您确定日志条目的来源。
+ 包含生成日志条目的 Rust 模块路径。
+ 日志消息文本。

跟踪模块的标准输出格式使用 ANSI 转义码对输出进行着色。筛选或搜索输出时，请记住这些转义序列。

**注意**  
嵌套跨度集中显示的 `sdk_invocation_id` 是由 SDK 在客户端生成的唯一 ID，用于帮助关联日志消息。它与在 AWS 服务的响应中找到的请求 ID 无关。

## 微调日志记录级别
<a name="logging-control"></a>

如果您使用支持环境筛选的 crate（例如 `tracing_subscriber`），则可以按模块控制日志的详细程度。

您可以为每个模块开启相同的日志记录级别。以下内容将每个模块的日志记录级别设置为了 `trace`：

```
$ RUST_LOG=trace cargo run
```

您可以为特定模块开启跟踪级别日志记录。在以下示例中，只有来自 `aws_smithy_runtime` 的日志才会进入 `trace` 级别。

```
$ RUST_LOG=aws_smithy_runtime=trace
```

您可以用逗号分隔多个模块，从而为它们指定不同的日志级别。以下示例将 `aws_config` 模块设置为 `trace` 级别日志记录，将 `aws_smithy_runtime` 模块设置为 `debug` 级别日志记录。

```
$ RUST_LOG=aws_config=trace,aws_smithy_runtime=debug cargo run
```

下表列出了可用于筛选日志消息的一些模块：


| Prefix | 描述 | 
| --- | --- | 
|  `aws_smithy_runtime`  |  请求和响应线路日志记录  | 
|  `aws_config`  |  凭证加载  | 
|  `aws_sigv4`  |  请求签名和规范请求  | 

要确定需要在日志输出中包含哪些模块，一种方法是先记录所有内容，然后在日志输出中找到 crate 名称以获取所需的信息。然后，您可以相应地设置环境变量并再次运行程序。

# 在中配置客户端终端节点 适用于 Rust 的 AWS SDK
<a name="endpoints"></a>

当 适用于 Rust 的 AWS SDK 调用 a 时 AWS 服务，其第一步之一就是确定将请求路由到何处。此过程称为端点解析。

在创建服务客户端时，您可以为 SDK 配置端点解析。端点解析的默认配置通常没问题，但您可能出于多种原因需要修改默认配置。两个示例原因如下所示：
+ 向服务的预发行版本或服务的本地部署发出请求。
+ 访问尚未在 SDK 中建模的特定服务功能。

**警告**  
端点解析是一个高级 SDK 主题。如果您更改默认设置，则可能会破坏代码。默认设置应用于生产环境中的大多数用户。

可以全局设置自定义终端节点，以便它们用于所有服务请求，也可以为特定的终端节点设置自定义终端节点 AWS 服务。

可以使用共享 AWS `config`文件中的环境变量或设置来配置自定义终端节点。有关此方法的信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考指南*》中的[服务特定端点](https://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html)。有关所有共享`config`文件设置和环境变量的完整列表 AWS 服务，请参阅[服务特定端点的标识符](https://docs.aws.amazon.com/sdkref/latest/guide/ss-endpoints-table.html)。

 或者，您也可以在代码中配置此自定义选项，如以下部分所示。

## 自定义配置
<a name="custom-configuration"></a>

您可以使用在构建客户端时可用的两种方法来自定义服务客户端的端点解析：

1. `endpoint_url(url: Into<String>)`

1. `endpoint_resolver(resolver: impl crate::config::endpoint::ResolveEndpoint + `static)`

您可以设置这两个属性。但是，大多数情况下，您只提供一个。对于常规使用情况，`endpoint_url` 通常需要自定义。

### 设置端点 URL
<a name="set-endpoint-url"></a>

您可以为 `endpoint_url` 设置一个值来表示服务的“基本”主机名。但是，此值不是最终值，因为它是作为参数传递给客户端 `ResolveEndpoint` 实例的。然后，`ResolveEndpoint` 实现会检查该值，并可能修改该值以确定最终端点。

### 设置端点解析器
<a name="set-endpoint-resolver"></a>

服务客户端的 `ResolveEndpoint` 实现决定了 SDK 用于任何给定请求的最终解析端点。服务客户端为每个请求调用 `resolve_endpoint` 方法，并使用解析器返回的 [https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/endpoint/struct.EndpointFuture.html](https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/endpoint/struct.EndpointFuture.html) 值，而不做任何更改。

以下示例演示了如何为 Amazon S3 客户端提供自定义端点解析器实现，该实现会根据不同的阶段（例如暂存和生产）解析不同的端点：

```
use aws_sdk_s3::config::endpoint::{ResolveEndpoint, EndpointFuture, Params, Endpoint};

#[derive(Debug)]
struct StageResolver { stage: String }
impl ResolveEndpoint for StageResolver {
    fn resolve_endpoint(&self, params: &Params) -> EndpointFuture<'_> {
        let stage = &self.stage;
        EndpointFuture::ready(Ok(Endpoint::builder().url(format!("{stage}.myservice.com")).build()))
    }
}


let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

let resolver = StageResolver { stage: std::env::var("STAGE").unwrap() };

let s3_config = aws_sdk_s3::config::Builder::from(&config)
    .endpoint_resolver(resolver)
    .build();

let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

**注意**  
端点解析器以及由此扩展的 `ResolveEndpoint` 特性是每个服务特有的，因此只能在服务客户端配置中进行配置。另一方面，可以使用共享配置（应用于从中派生的所有服务）或针对特定服务配置端点 URL。

#### ResolveEndpoint 参数
<a name="resolveendpoint-parameters"></a>

`resolve_endpoint` 方法接受包含端点解析中使用的属性的服务特定参数。

每个服务均包含以下基本属性：


| Name | Type | 说明 | 
| --- | --- | --- | 
| region | 字符串 | 客户的 AWS 区域 | 
| endpoint | 字符串 | endpointUrl 的值集的字符串表示形式 | 
| use\$1fips | 布尔值 | 是否在客户端配置中启用了 FIPS 端点 | 
| use\$1dual\$1stack | 布尔值 | 是否在客户端配置中启用了双栈端点 | 

AWS 服务 可以指定解析所需的其他属性。例如，Amazon S3 [端点参数](https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/endpoint/struct.Params.html)包括存储桶名称和几个特定于 Amazon S3 的功能设置。例如，`force_path_style` 属性决定是否可以使用虚拟主机寻址。

如果您实施自己的提供程序，则无需构建自己的端点参数实例。SDK 为每个请求提供属性并将其传递给您的 `resolve_endpoint` 实现。

### 将使用 `endpoint_url` 与使用 `endpoint_resolver` 进行比较
<a name="endpoint-url-or-endpoint-resolver"></a>

需要注意的是，以下两种配置（一种使用 `endpoint_url`，另一种使用 `endpoint_resolver`）产生的客户端在端点解析行为上并不相同。

```
use aws_sdk_s3::config::endpoint::{ResolveEndpoint, EndpointFuture, Params, Endpoint};

#[derive(Debug, Default)]
struct CustomResolver;
impl ResolveEndpoint for CustomResolver {
    fn resolve_endpoint(&self, _params: &Params) -> EndpointFuture<'_> {
        EndpointFuture::ready(Ok(Endpoint::builder().url("https://endpoint.example").build()))
    }
}

let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

// use endpoint url
aws_sdk_s3::config::Builder::from(&config)
    .endpoint_url("https://endpoint.example")
    .build();
    
// Use endpoint resolver
aws_sdk_s3::config::Builder::from(&config)
    .endpoint_resolver(CustomResolver::default())
    .build();
```

设置 `endpoint_url` 的客户端会指定传递给（默认）提供程序的*基本* URL，该 URL 可以作为端点解析的一部分进行修改。

设置 `endpoint_resolver` 的客户端指定 Amazon S3 客户端使用的*最终* URL。

## 示例
<a name="endpointsExamples"></a>

自定义端点通常用于测试。不是向基于云的服务发送调用，而是将调用路由到本地托管的模拟服务。其中两种选项是：
+ [DynamoDB local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) – Amazon DynamoDB 服务的本地版本。
+ [LocalStack](https://github.com/localstack/localstack)— 在本地计算机的容器中运行的云服务模拟器。

 以下示例说明了指定自定义端点以使用这两个测试选项的两种不同方法。

### 直接在代码中使用 DynamoDB local
<a name="endpointsExamplesddb"></a>

如前几节所述，您可以直接在代码中设置 `endpoint_url` 来覆盖基本端点，以便指向本地 DynamoDB 服务器。在代码中：

```
    let config = aws_config::defaults(aws_config::BehaviorVersion::latest())
        .test_credentials()
        // DynamoDB run locally uses port 8000 by default.
        .endpoint_url("http://localhost:8000")
        .load()
        .await;
    let dynamodb_local_config = aws_sdk_dynamodb::config::Builder::from(&config).build();

    let client = aws_sdk_dynamodb::Client::from_conf(dynamodb_local_config);
```

[完整的示例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/dynamodb/src/bin/list-tables-local.rs)可在上找到 GitHub。

### LocalStack 使用该`config`文件
<a name="endpointsExamplesLs"></a>

您可以在共享 AWS `config`文件中设置[特定于服务的终端节点](https://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html)。以下配置的配置文件将 `endpoint_url` 设置为连接到端口 `4566` 上的 `localhost`。有关 LocalStack 配置的更多信息，请参阅*LocalStack文档*网站[上的 LocalStack 通过端点 URL 进行访问](https://docs.localstack.cloud/references/network-troubleshooting/endpoint-url/)。

```
[profile localstack]
region=us-east-1
endpoint_url = http://localhost:4566
```

当您使用 `localstack` 配置文件时，SDK 将获取共享 `config` 文件中的更改并将其应用到您的 SDK 客户端。使用这种方法，您的代码无需包含对端点的任何引用，如下所示：

```
    // set the environment variable `AWS_PROFILE=localstack` when running
    // the application to source `endpoint_url` and point the SDK at the
    // localstack instance
    let config = aws_config::defaults(BehaviorVersion::latest()).load().await;

    let s3_config = aws_sdk_s3::config::Builder::from(&config)
        .force_path_style(true)
        .build();

    let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

[完整的示例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/localstack)可在上找到 GitHub。

# 在适用于 Rust 的 AWS SDK 中覆盖客户端的单个操作配置
<a name="peroperation"></a>

[创建服务客户端](config-code.md)后，配置将变为不可变并将应用于所有后续操作。虽然此时无法修改配置，但可以按操作对其进行覆盖。

每个操作生成器都有一种可用于创建 `CustomizableOperation` 的 `customize` 方法，以便您可以覆盖现有配置的单个副本。原始客户端配置将保持不变。

以下示例展示了创建 Amazon S3 客户端的过程，该客户端调用两个操作，其中第二个操作被覆盖以发送到另一个 AWS 区域。Amazon S3 的所有对象调用都使用 `us-east-1` 区域，除非 API 调用被显式覆盖以使用修改后的 `us-west-2`。

```
use aws_config::{BehaviorVersion, Region};

let config = aws_config::defaults(BehaviorVersion::latest())
    .region("us-east-1")
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);

// Request will be sent to "us-east-1"
s3.list_buckets()
    .send()
    .await?;

// Unset fields default to using the original config value
let modified = aws_sdk_s3::Config::builder()
    .region(Region::from_static("us-west-2"));

// Request will be sent to "us-west-2"
s3.list_buckets()
   // Creates a CustomizableOperation
    .customize()
    .config_override(modified)
    .send()
    .await?;
```

**注意**  
上述示例针对的是 Amazon S3，但是概念对所有操作都是一样的。某些操作可能在 `CustomizeableOperation` 方面有其他方法。

有关使用 `customize` 为单个操作添加拦截器的示例，请参阅[仅用于拦截特定操作的拦截器](interceptors.md#interceptors-registration-specific)。

# 在 Rust AWS 开发工具包中配置 HTTP 级别的设置
<a name="http"></a>

 适用于 Rust 的 AWS SDK 提供了内置 HTTP 功能，供您在代码中创建的 AWS 服务 客户端使用。

默认情况下，适用于 Rust 的 SDK 使用基于 `hyper`、`rustls` 和 `aws-lc-rs` 的 HTTPS 客户端。此客户端应该适用于大多数使用案例，而无需其他配置。
+ [https://docs.rs/hyper/latest/hyper/](https://docs.rs/hyper/latest/hyper/)是 Rust 的较低级别 HTTP 库，可以与一起使用 适用于 Rust 的 AWS SDK 来调用 API 服务。
+ [https://github.com/rustls/rustls](https://github.com/rustls/rustls) 是一个用 Rust 编写的现代 TLS 库，它为加密提供程序提供了内置选项。
+ [https://github.com/aws/aws-lc](https://github.com/aws/aws-lc) 是一个通用加密库，包含 TLS 和常见应用程序所需的算法。
+ [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) 是 Rust 中用于 `aws-lc` 库的惯用包装器。

如果您想选择其他 TLS 或加密提供程序，`aws-smithy-http-client` 提供了一些其他选项和配置。对于更高级的使用案例，我们鼓励您自带 HTTP 客户端实现或提交功能申请以供考虑。

## 选择替代 TLS 提供程序
<a name="tlsProviders"></a>

`aws-smithy-http-client` crate 提供了一些替代 TLS 提供程序。

提供以下提供程序：

**`rustls` 与 `aws-lc`**  
基于 [https://github.com/rustls/rustls](https://github.com/rustls/rustls) 的 TLS 提供程序，使用 [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) 进行加密。  
这是适用于 Rust 的 SDK 的默认 HTTP 行为。如果您想使用此选项，则无需在代码中执行任何其他操作。

**`s2n-tls`**  
基于 [https://github.com/aws/s2n-tls](https://github.com/aws/s2n-tls) 的 TLS 提供程序。

**`rustls` 与 `aws-lc-fips`**  
基于 [https://github.com/rustls/rustls](https://github.com/rustls/rustls) 的 TLS 提供程序，使用符合 FIPS 标准的 [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) 版本进行加密

**`rustls` 与 `ring`**  
基于 [https://github.com/rustls/rustls](https://github.com/rustls/rustls) 的 TLS 提供程序，使用 [https://github.com/briansmith/ring](https://github.com/briansmith/ring) 进行加密。

### 先决条件
<a name="prereqTls"></a>

使用 `aws-lc-rs` 或 `s2n-tls` 需要 C 编译器（Clang 或 GCC）来构建。对于某些平台，构建可能还需要 CMake。在任何平台上使用 “fips” 功能进行构建都需要 CMake 然后开始。有关更多信息，请参阅[适用于 Rust 的 AWS Libcrypto（`aws-lc-rs`）](https://github.com/aws/aws-lc-rs/blob/main/aws-lc-rs/README.md)存储库和构建说明。

### 如何使用替代 TLS 提供程序
<a name="s2nTls"></a>

`aws-smithy-http-client` crate 提供了其他 TLS 选项。要让您的 AWS 服务 客户端使用其他 TLS 提供程序，请使用 `aws_config` crate 中的加载器覆盖 `http_client`。HTTP 客户端既用于 AWS 服务 ，也用于凭证提供程序。

以下示例演示了如何使用 `s2n-tls` TLS 提供程序。但是，类似的方法也适用于其他提供程序。

要编译示例代码，请运行以下命令向项目添加依赖项：

```
cargo add aws-smithy-http-client -F s2n-tls
```

示例代码：

```
use aws_smithy_http_client::{tls, Builder};

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::S2nTls)
        .build_https();

    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;

    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

## 启用 FIPS 支持
<a name="fipsTls"></a>

`aws-smithy-http-client` crate 提供了启用符合 FIPS 标准的加密实现的选项。要让您的 AWS 服务 客户使用符合 FIPS 标准的提供商，请`http_client`使用箱子中的加载器替换。`aws_config`HTTP 客户端既 AWS 服务 用于证书提供者，也用于凭证提供程序。

**注意**  
FIPS 支持需要在构建环境中添加其他依赖项。请参阅 `aws-lc` crate 的[构建](https://github.com/aws/aws-lc/blob/main/BUILDING.md)说明。

要编译示例代码，请运行以下命令向项目添加依赖项：

```
cargo add aws-smithy-http-client -F rustls-aws-lc-fips
```

以下示例代码可启用 FIPS 支持：

```
// file: main.rs
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder,
};

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLcFips))
        .build_https();

    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;

    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

## 优先考虑后量子密钥交换
<a name="quantumTls"></a>

默认 TLS 提供程序基于使用 `aws-lc-rs` 的 `rustls`，支持 `X25519MLKEM768` 后量子密钥交换算法。要使 `X25519MLKEM768` 成为优先级最高的算法，您需要将 `rustls` 程序包添加到 crate 中并启用 `prefer-post-quantum` 功能标志。否则，它可用，但不是最高优先级。有关更多信息，请参阅`rustls`[文档](https://docs.rs/rustls/0.23.23/rustls/manual/_05_defaults/index.html#about-the-post-quantum-secure-key-exchange-x25519mlkem768)。

**注意**  
这将在未来版本中成为默认选项。

## 覆盖 DNS 解析器
<a name="overrideDns"></a>

 通过手动配置 HTTP 客户端，可以覆盖默认 DNS 解析器。

要编译示例代码，请运行以下命令向项目添加依赖项：

```
cargo add aws-smithy-http-client -F rustls-aws-lc
cargo add aws-smithy-runtime-api -F client
```

以下示例代码覆盖 DNS 解析器：

```
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder
};
use aws_smithy_runtime_api::client::dns::{DnsFuture, ResolveDns};
use std::net::{IpAddr, Ipv4Addr};

/// A DNS resolver that returns a static IP address (127.0.0.1)
#[derive(Debug, Clone)]
struct StaticResolver;

impl ResolveDns for StaticResolver {
    fn resolve_dns<'a>(&'a self, _name: &'a str) -> DnsFuture<'a> {
        DnsFuture::ready(Ok(vec![IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))]))
    }
}

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLc))
        .build_with_resolver(StaticResolver);
    
    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;
    
    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

**注意**  
默认情况下，亚马逊 Linux 2023 (AL2023) 不会在操作系统级别缓存 DNS。

## 自定义根 CA 证书
<a name="customizeCertificatesTls"></a>

默认情况下，TLS 提供程序会加载给定平台的系统原生根证书。要自定义此行为以加载自定义 CA 捆绑包，您可以使用自己的 `TrustStore` 配置 `TlsContext`。

要编译示例代码，请运行以下命令向项目添加依赖项：

```
cargo add aws-smithy-http-client -F rustls-aws-lc
```

以下示例结合使用了 `rustls` 和 `aws-lc`，但也适用于任何受支持的 TLS 提供程序：

```
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder
};
use std::fs;

/// read the PEM encoded root CA (bundle) and return a custom TLS context
fn tls_context_from_pem(filename: &str) -> tls::TlsContext {
    let pem_contents = fs::read(filename).unwrap();
    
    // Create a new empty trust store (this will not load platform native certificates)
    let trust_store = tls::TrustStore::empty()
        .with_pem_certificate(pem_contents.as_slice());
        
    tls::TlsContext::builder()
        .with_trust_store(trust_store)
        .build()
        .expect("valid TLS config")
}

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLc))
        .tls_context(tls_context_from_pem("my-custom-ca.pem"))
        .build_https();
    
    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;
    
    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

# 在 Rust AWS 开发工具包中配置拦截器
<a name="interceptors"></a>

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

以下示例显示了一个简单的拦截器，该拦截器会在进入重试循环之前向所有传出请求添加一个额外的标头：

```
use std::borrow::Cow;
use aws_smithy_runtime_api::client::interceptors::{
    Intercept,
    context::BeforeTransmitInterceptorContextMut,   
};
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use aws_smithy_types::config_bag::ConfigBag;
use aws_smithy_runtime_api::box_error::BoxError;

#[derive(Debug)]
struct AddHeaderInterceptor {
    key: Cow<'static, str>,
    value: Cow<'static, str>,
}

impl AddHeaderInterceptor {
    fn new(key: &'static str, value: &'static str) -> Self {
        Self {
            key: Cow::Borrowed(key),
            value: Cow::Borrowed(value),
        }
    }
}

impl Intercept for AddHeaderInterceptor {
    fn name(&self) -> &'static str {
        "AddHeader"
    }

    fn modify_before_retry_loop(
        &self,
        context: &mut BeforeTransmitInterceptorContextMut<'_>,
        _runtime_components: &RuntimeComponents,
        _cfg: &mut ConfigBag,
    ) -> Result<(), BoxError> {
        let headers = context.request_mut().headers_mut();
        headers.insert(self.key.clone(), self.value.clone());

        Ok(())
    }
}
```

有关更多信息和可用的拦截器钩子，请参阅[拦截](https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/interceptors/trait.Intercept.html)特性。

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

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

### 用于拦截服务客户端上所有操作的拦截器
<a name="interceptors-registration-all"></a>

要为整个客户端注册拦截器，请使用 `Builder` 模式添加拦截器。

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;
    
// All service operations invoked using 's3' will have the header added.
let s3_conf = aws_sdk_s3::config::Builder::from(&config)
    .interceptor(AddHeaderInterceptor::new("x-foo-version", "2.7"))
    .build();

let s3 = aws_sdk_s3::Client::from_conf(s3_conf);
```

### 仅用于拦截特定操作的拦截器
<a name="interceptors-registration-specific"></a>

要仅为单个操作注册拦截器，请使用 `customize` 扩展程序。您可以使用此方法在每个操作级别覆盖服务客户端配置。有关可自定义的操作的更多信息，请参阅[在适用于 Rust 的 AWS SDK 中覆盖客户端的单个操作配置](peroperation.md)。

```
// Only the list_buckets operation will have the header added.
s3.list_buckets()
    .customize()
    .interceptor(AddHeaderInterceptor::new("x-bar-version", "3.7"))
    .send()
    .await?;
```