

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

# 迁移到 适用于 Go 的 AWS SDK v2
<a name="migrate-gosdk"></a>

## 最低 Go 版本
<a name="minimum-go-version"></a>

 适用于 Go 的 AWS SDK 需要最低版本的 Go 1.23。可以在[下载](https://go.dev/dl/)页面下载最新版本的 Go。有关每个 Go 版本发行的更多信息以及升级所需的相关信息，请参阅[发行历史记录](https://go.dev/doc/devel/release)。

## 模块化
<a name="modularization"></a>

 适用于 Go 的 AWS SDK 已更新，以利用 Go 模块的优势，该模块已成为 Go 1.13 中的默认开发模式。SDK 提供的许多程序包已实现模块化，并分别独立进行版本控制和发行。此更改使得应用程序依赖项建模得到改进，并使 SDK 能够提供遵循 Go 模块版本控制策略的新特征和功能。

 以下列表列出了 SDK 提供的一些 Go 模块：


|  模块  |  说明  | 
| --- | --- | 
|  github.com/aws/aws-sdk-go-v2  |  SDK 核心  | 
|  github.com/aws/aws-sdk-go-v2/config  |  共享配置加载  | 
|  github.com/aws/aws-sdk-go-v2/credentials  |  AWS 凭证提供商  | 
|  github.com/aws/aws-sdk-go-v2/feature/ec2/imds  |  Amazon EC2 实例元数据服务客户端  | 

 SDK 的服务客户端和更高级别的实用程序模块均嵌套在以下导入路径下：


|  导入根  |  说明  | 
| --- | --- | 
|  github.com/aws/aws-sdk-go-v2/service/  |  服务客户端模块  | 
|  github.com/aws/aws-sdk-go-v2/feature/  |  适用于 Amazon S3 Transfer Manager 等服务的高级别实用程序  | 

## 配置加载
<a name="configuration-loading"></a>

 [session](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/) 程序包和相关功能替换为 [config](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config) 程序包提供的简化配置系统。`config` 程序包是一个单独的 Go 模块，可以通过与 `go get` 配合，包含在应用程序的依赖项中。

```
go get github.com/aws/aws-sdk-go-v2/config
```

 [Session.new](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/#New)[，会话。 ](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/#NewSession)NewSession[NewSessionWithOptions](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/#NewSessionWithOptions)[、和 [session.必须](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/#Must)迁移到配置中。 LoadDefaultConfig](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#LoadDefaultConfig)。

 `config` 程序包提供了多个帮助程序函数，可帮助以编程方式覆盖共享配置加载。这些函数名称以 `With` 为前缀，后跟它们覆盖的选项。我们来看一些关于如何迁移 `session` 程序包使用情况的示例。

 有关加载共享配置的更多信息，请参阅[配置 SDK](configure-gosdk.md)。

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

#### 从迁移 NewSession 到 LoadDefaultConfig
<a name="migrating-from-newsession-to-loaddefaultconfig"></a>

 以下示例演示了如何在不使用其他参数的情况下将 `session.NewSession` 的使用情况迁移到 `config.LoadDefaultConfig`。

```
// V1 using NewSession

import "github.com/aws/aws-sdk-go/aws/session"

// ...

sess, err := session.NewSession()
if err != nil {
    // handle error
}
```

```
// V2 using LoadDefaultConfig

import "context"
import "github.com/aws/aws-sdk-go-v2/config"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    // handle error
}
```

#### NewSession 使用 AWS.config 选项从中迁移
<a name="migrating-from-newsession-with-awsconfig-options"></a>

 该示例演示了如何在配置加载期间迁移 `aws.Config` 值的覆盖。可以向 `config.LoadDefaultConfig` 提供一个或多个 `config.With*` 帮助程序函数来覆盖加载的配置值。[在此示例中， AWS 区域被重写为`us-west-2`使用配置。 WithRegion](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#WithRegion)辅助函数。

```
// V1

import "github.com/aws/aws-sdk-go/aws"
import "github.com/aws/aws-sdk-go/aws/session"

// ...

sess, err := session.NewSession(aws.Config{
    Region: aws.String("us-west-2")
})
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/config"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO(),
    config.WithRegion("us-west-2"),
)
if err != nil {
    // handle error
}
```

#### 迁移自 NewSessionWithOptions
<a name="migrating-from-newsessionwithoptions"></a>

 此示例演示了如何在配置加载期间迁移覆盖值。可以向 `config.LoadDefaultConfig` 提供零个或多个 `config.With*` 帮助程序函数来覆盖加载的配置值。在此示例中，我们展示了如何覆盖加载 AWS SDK 共享配置时使用的目标配置文件。

```
// V1

import "github.com/aws/aws-sdk-go/aws"
import "github.com/aws/aws-sdk-go/aws/session"

// ...

sess, err := session.NewSessionWithOptions(aws.Config{
    Profile: "my-application-profile"
})
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/config"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO(),
    config.WithSharedConfigProfile("my-application-profile"),
)
if err != nil {
    // handle error
}
```

## 模拟和 `*iface`
<a name="mocking-and-iface"></a>

 其中的 `*iface` 程序包和接口（例如 [s3iface.S3API](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3iface/#S3API)）已被删除。这些接口定义并不稳定，因为每当有服务添加新操作时，都会破坏这些定义。

 对于正在使用的服务操作，应将 `*iface` 的使用情况替换为调用方定义的作用域接口：

```
// V1

import "io"

import "github.com/aws/aws-sdk-go/service/s3"
import "github.com/aws/aws-sdk-go/service/s3/s3iface"

func GetObjectBytes(client s3iface.S3API, bucket, key string) ([]byte, error) {
    object, err := client.GetObject(&s3.GetObjectInput{
        Bucket: &bucket,
        Key:    &key,
    })
    if err != nil {
        return nil, err
    }
    defer object.Body.Close()

    return io.ReadAll(object.Body)
}
```

```
// V2

import "context"
import "io"

import "github.com/aws/aws-sdk-go-v2/service/s3"

type GetObjectAPIClient interface {
    GetObject(context.Context, *s3.GetObjectInput, ...func(*s3.Options)) (*s3.GetObjectOutput, error)
}

func GetObjectBytes(ctx context.Context, client GetObjectAPIClient, bucket, key string) ([]byte, error) {
    object, err := client.GetObject(ctx, &s3.GetObjectInput{
        Bucket: &bucket,
        Key:    &key,
    })
    if err != nil {
        return nil, err
    }
    defer object.Body.Close()

    return io.ReadAll(object.Body)
}
```

 有关更多信息，请参阅[使用适用于 Go 的 AWS SDK v2 进行单元测试](unit-testing.md)。

## 凭证和凭证提供程序
<a name="credentials--credential-providers"></a>

 [aws/credentials](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/) 程序包和关联的凭证提供程序已重新定位到 [credentials](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials) 程序包的位置。`credentials` 程序包是一个 Go 模块，您可以使用 `go get` 来检索该模块。

```
go get github.com/aws/aws-sdk-go-v2/credentials
```

 适用于 Go 的 AWS SDK v2 版本更新了 AWS 凭证提供程序，为检索 AWS 凭证提供了一致的接口。每个提供商都实现了 a [ws。 CredentialsProvider](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#CredentialsProvider)接口，它`Retrieve`定义了一个返回`(aws.Credentials, error)`. [AWS.Credentials 类似于 v1 凭证.](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Credentials) [Value 类型 适用于 Go 的 AWS SDK 。](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/#Value)

 必须使用 a [w `aws.CredentialsProvider` s 包装对象。 CredentialsCache](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#CredentialsCache)以允许进行凭据缓存。你[NewCredentialsCache](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#NewCredentialsCache)用来构造一个`aws.CredentialsCache`对象。默认情况下，使用 `aws.CredentialsCache` 对由 `config.LoadDefaultConfig` 配置的凭证进行包装。

 下表列出了从 适用于 Go 的 AWS SDK v1 到 v2 的 AWS 证书提供商的位置变化。


|  Name  |  V1 导入  |  V2 导入  | 
| --- | --- | --- | 
|  亚马逊 EC2 IAM 角色证书  |  github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds  |  github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds  | 
|  端点凭证  |  github.com/aws/aws-sdk-go/aws/credentials/endpointcreds  |  github.com/aws/aws-sdk-go-v2/credentials/endpointcreds  | 
|  进程凭证  |  github.com/aws/aws-sdk-go/aws/credentials/processcreds  |  github.com/aws/aws-sdk-go-v2/credentials/processcreds  | 
|  AWS Security Token Service  |  github.com/aws/aws-sdk-go/aws/credentials/stscreds  |  github.com/aws/aws-sdk-go-v2/credentials/stscreds  | 

### 静态凭证
<a name="static-credentials"></a>

 使用[凭证的应用程序。 ](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials//#NewStaticCredentials)NewStaticCredentials[要以编程方式构造静态凭证，必须使用证书。 NewStaticCredentialsProvider](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials#NewStaticCredentialsProvider)。

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

```
// V1

import "github.com/aws/aws-sdk-go/aws/credentials"

// ...

appCreds := credentials.NewStaticCredentials(accessKey, secretKey, sessionToken)
value, err := appCreds.Get()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/credentials"

// ...

appCreds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKey, secretKey, sessionToken))
value, err := appCreds.Retrieve(context.TODO())
if err != nil {
    // handle error
}
```

### 亚马逊 EC2 IAM 角色证书
<a name="ec2-iam-role-credentials"></a>

 必须迁移[NewCredentials](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/ec2rolecreds/#NewCredentials)和的使用[NewCredentialsWithClient](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/ec2rolecreds/#NewCredentialsWithClient)才能使用 [New](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds#New)。

 该`ec2rolecreds`软件包以 `ec2rolecreds.New` [ec2rolecreds.Options 的功能选项](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds#Options)作为输入，允许您覆盖要使用的特定亚马逊 EC2 实例元数据服务客户端，或者覆盖证书到期窗口。

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

```
// V1

import "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"

// ...

appCreds := ec2rolecreds.NewCredentials(sess)
value, err := appCreds.Get()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds"

// ...

// New returns an object of a type that satisfies the aws.CredentialProvider interface
appCreds := aws.NewCredentialsCache(ec2rolecreds.New())
value, err := appCreds.Retrieve(context.TODO())
if err != nil {
    // handle error
}
```

### 端点凭证
<a name="endpoint-credentials"></a>

 必须迁移[NewCredentialsClient](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/endpointcreds/#NewCredentialsClient)和的使用[NewProviderClient](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/endpointcreds/#NewProviderClient)才能使用 [New](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds#New)。

 `endpointcreds` 程序包的 `New` 函数采用字符串参数（其中包含要从中检索凭证的 HTTP 或 HTTPS 端点的 URL）和 [endpointcreds.Options](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds#Options) 的函数选项来更改凭证提供程序并覆盖特定的配置设置。

### 进程凭证
<a name="process-credentials"></a>

 必须迁移[NewCredentials[NewCredentialsCommand](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/processcreds/#NewCredentialsCommand)](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/processcreds/#NewCredentials)、和的使用[NewCredentialsTimeout](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/processcreds/#NewCredentialsTimeout)才能使用[NewProvider](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/processcreds#New)或[NewProviderCommand](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/processcreds#NewProviderCommand)。

 `processcreds` 程序包的 `NewProvider` 函数采用字符串参数（要在主机环境的 shell 中执行的命令）和 [Options](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/processcreds#Options) 的函数选项来更改凭证提供程序并覆盖特定的配置设置。

 `NewProviderCommand`采用接口的实现，该[NewCommandBuilder](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/processcreds#NewCommandBuilder)接口定义了更复杂的进程命令，这些命令可能采用一个或多个命令行参数，或者具有特定的执行环境要求。 [DefaultNewCommandBuilder](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/processcreds#DefaultNewCommandBuilder)实现此接口，并为需要多个命令行参数的进程定义命令生成器。

#### 示例
<a name="example-2"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/credentials/processcreds"

// ...

appCreds := processcreds.NewCredentials("/path/to/command")
value, err := appCreds.Get()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/credentials/processcreds"

// ...

appCreds := aws.NewCredentialsCache(processcreds.NewProvider("/path/to/command"))
value, err := appCreds.Retrieve(context.TODO())
if err != nil {
    // handle error
}
```

### AWS Security Token Service 凭证
<a name="stslong-credentials"></a>

#### AssumeRole
<a name="assumerole"></a>

 必须迁移和的[NewCredentials](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/#NewCredentials)使用情况[NewCredentialsWithClient](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/#NewCredentialsWithClient)才能使用[NewAssumeRoleProvider](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#NewAssumeRoleProvider)。

 必须使用 [STS.Client](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/sts#Client) 调用`stscreds`包的`NewAssumeRoleProvider`函数，并使用提供`sts.Client`者配置的凭据假设角色 AWS Identity and Access Management ARN。您还可以提供一组的功能选项[AssumeRoleOptions](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#AssumeRoleOptions)来修改提供程序的其他可选设置。

##### 示例
<a name="example-3"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/credentials/stscreds"

// ...

appCreds := stscreds.NewCredentials(sess, "arn:aws:iam::123456789012:role/demo")
value, err := appCreds.Get()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/credentials/stscreds"
import "github.com/aws/aws-sdk-go-v2/service/sts"

// ...

client := sts.NewFromConfig(cfg)

appCreds := stscreds.NewAssumeRoleProvider(client, "arn:aws:iam::123456789012:role/demo")
value, err := appCreds.Retrieve(context.TODO())
if err != nil {
    // handle error
}
```

#### AssumeRoleWithWebIdentity
<a name="assumerolewithwebidentity"></a>

 必须迁移[NewWebIdentityCredentials[NewWebIdentityRoleProvider](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/#NewWebIdentityRoleProvider)](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/#NewWebIdentityCredentials)、和的使用[NewWebIdentityRoleProviderWithToken](https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/#NewWebIdentityRoleProviderWithToken)才能使用[NewWebIdentityRoleProvider](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#NewWebIdentityRoleProvider)。

 必须使用 [sts.Client](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/sts#Client) 调用`stscreds`包的`NewWebIdentityRoleProvider`函数，并使用提供者配置的凭据来假设角色 AWS Identity and Access Management ARN，以及[IdentityTokenRetriever](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#IdentityTokenRetriever)用于提供 `sts.Client` 2.0 或 OAuth OpenID Connect ID 令牌的实现。 [IdentityTokenFile](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#IdentityTokenFile)可以`IdentityTokenRetriever`用来从位于应用程序主机文件系统上的文件中提供 Web 身份令牌。您还可以提供一组功能选项[WebIdentityRoleOptions](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#WebIdentityRoleOptions)来修改提供者的其他可选设置。

##### 示例
<a name="example-4"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/credentials/stscreds"

// ...

appCreds := stscreds.NewWebIdentityRoleProvider(sess, "arn:aws:iam::123456789012:role/demo", "sessionName", "/path/to/token")
value, err := appCreds.Get()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/credentials/stscreds"
import "github.com/aws/aws-sdk-go-v2/service/sts"

// ...

client := sts.NewFromConfig(cfg)

appCreds := aws.NewCredentialsCache(stscreds.NewWebIdentityRoleProvider(
        client,
        "arn:aws:iam::123456789012:role/demo",
        stscreds.IdentityTokenFile("/path/to/file"),
        func(o *stscreds.WebIdentityRoleOptions) {
            o.RoleSessionName = "sessionName"
        }))
value, err := appCreds.Retrieve(context.TODO())
if err != nil {
    // handle error
}
```

## 客户端服务
<a name="service-clients"></a>

 适用于 Go 的 AWS SDK 提供嵌套在`github.com/aws/aws-sdk-go-v2/service`导入路径下的服务客户端模块。每个服务客户端都包含在一个 Go 程序包中，该程序包使用每项服务的唯一标识符进行标识。下表提供了 适用于 Go 的 AWS SDK中服务导入路径的一些示例。


|  服务名称  |  V1 导入路径  |  V2 导入路径  | 
| --- | --- | --- | 
|  Amazon S3  |  github.com/aws/aws-sdk-go/service/s3  |  github.com/aws/aws-sdk-go-v2/service/s3  | 
|  Amazon DynamoDB  |  github.com/aws/aws-sdk-go/service/dynamodb  |  github.com/aws/aws-sdk-go-v2/service/dynamodb  | 
|  Amazon CloudWatch 日志  |  github.com/aws/aws-sdk-go/service/cloudwatchlogs  |  github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs  | 

 每个服务客户端程序包都是一个独立版本的 Go 模块。要将服务客户端添加为应用程序的依赖项，请使用带有服务导入路径的 `go get` 命令。例如，要将 Amazon S3 客户端添加到依赖项中，请使用 

```
go get github.com/aws/aws-sdk-go-v2/service/s3
```

### 客户端构造
<a name="client-construction"></a>

 您可以使用客户端包中的 适用于 Go 的 AWS SDK `New`或`NewFromConfig`构造函数在中构造客户端。从 适用于 Go 的 AWS SDK v1 迁移时，我们建议您使用`NewFromConfig`变体，该变体将使用中的值返回新的服务客户端。`aws.Config`在使用 `config.LoadDefaultConfig` 加载 SDK 共享配置时将会创建 `aws.Config` 值。有关创建服务客户端的详细信息，请参阅[将适用于 Go 的 AWS SDK v2 与 AWS 服务结合使用](use-services.md)。

#### 示例 1
<a name="w2aac43c13c11b5"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/session"
import "github.com/aws/aws-sdk-go/service/s3"

// ...

sess, err := session.NewSession()
if err != nil {
    // handle error
}

client := s3.New(sess)
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    // handle error
}

client := s3.NewFromConfig(cfg)
```

#### 示例 2：覆盖客户端设置
<a name="example-2-overriding-client-settings"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws"
import "github.com/aws/aws-sdk-go/aws/session"
import "github.com/aws/aws-sdk-go/service/s3"

// ...

sess, err := session.NewSession()
if err != nil {
    // handle error
}

client := s3.New(sess, &aws.Config{
    Region: aws.String("us-west-2"),
})
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    // handle error
}

client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.Region = "us-west-2"
})
```

### 端点
<a name="endpoints"></a>

 [endpoints](https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/) 程序包不再存在于 适用于 Go 的 AWS SDK中。现在，每个服务客户端都将其所需的 AWS 端点元数据嵌入到客户端包中。这样就不再包含应用程序未使用的服务的端点元数据，从而减少了已编译应用程序的总体二进制文件大小。

 此外，每项服务现在都提供自己的接口，用于在 `EndpointResolverV2` 中进行端点解析。每个 API 都会针对服务 `EndpointParameters` 采用一组独特的参数，这些参数的值由 SDK 在调用操作时从不同位置获取。

 默认情况下，服务客户端使用其配置的 AWS 区域来解析目标区域的服务终端节点。如果您的应用程序需要自定义端点，则可在 `aws.Config` 结构上的 `EndpointResolverV2` 字段中指定自定义行为。如果您的应用程序实现了自定义 [endpoints.Resolver](https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/#Resolver)，则必须将其迁移以符合这个新的按服务划分的接口。

 有关端点以及如何实施自定义解析器的更多信息，请参阅[配置客户端端点](configure-endpoints.md)。

### 身份验证
<a name="authentication"></a>

 适用于 Go 的 AWS SDK 支持更高级的身份验证行为，从而允许使用较新的 AWS 服务功能，例如 codecatalyst 和 S3 Express One Zone Zone。此外，可以针对每个客户端对此行为进行自定义。

### 调用 API 操作
<a name="invoking-api-operations"></a>

 服务客户端操作方法的数量已大幅减少。`<OperationName>Request`、`<OperationName>WithContext` 和 `<OperationName>` 方法均已合并为单个操作方法 `<OperationName>`。

#### 示例
<a name="example-5"></a>

 以下示例显示了如何将对 Amazon S3 PutObject 操作的调用从 适用于 Go 的 AWS SDK v1 迁移到 v2。

```
// V1

import "context"
import "github.com/aws/aws-sdk-go/service/s3"

// ...

client := s3.New(sess)

// Pattern 1
output, err := client.PutObject(&s3.PutObjectInput{
    // input parameters
})

// Pattern 2
output, err := client.PutObjectWithContext(context.TODO(), &s3.PutObjectInput{
    // input parameters
})

// Pattern 3
req, output := client.PutObjectRequest(context.TODO(), &s3.PutObjectInput{
    // input parameters
})
err := req.Send()
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

client := s3.NewFromConfig(cfg)

output, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
    // input parameters
})
```

### 服务数据类型
<a name="service-data-types"></a>

 操作的顶级输入和输出类型可在服务客户端程序包中找到。给定操作的输入和输出类型遵循 `<OperationName>Input` 和 `<OperationName>Output` 的模式，其中 `OperationName` 是您正在调用的操作的名称。例如，Amazon S3 PutObject 操作的输入和输出形状[PutObjectOutput](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#PutObjectOutput)分别为[PutObjectInput](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#PutObjectInput)和。

 除输入和输出类型之外的所有其他服务数据类型均已迁移到位于服务客户端程序包导入路径层次结构下的 `types` 程序包中。例如，s [3。 AccessControlPolicy](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#AccessControlPolicy)type 现在位于 typ [es。 AccessControlPolicy](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#AccessControlPolicy)。

#### 枚举值
<a name="enumeration-values"></a>

 SDK 现在为所有 API 枚举字段提供类型化体验。现在，您可以使用服务客户端 `types` 程序包中的一种具体类型，而不是使用从服务 API 参考文档中复制的字符串文本值。例如，您可以为 Amazon S3 PutObjectInput 操作提供要应用于对象的 ACL。在 适用于 Go 的 AWS SDK v1 中，此参数是一种`*string`类型。在中 适用于 Go 的 AWS SDK，此参数现在是[类型。 ObjectCannedACL](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#ObjectCannedACL)。`types` 程序包为可以分配给该字段的有效枚举值提供了生成的常量。例如[类型。 ObjectCannedACLPrivate](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#ObjectCannedACLPrivate)是 “私有” 固定 ACL 值的常数。该值可用来代替管理应用程序中的字符串常量。

### 指针参数
<a name="pointer-parameters"></a>

 适用于 Go 的 AWS SDK v1 要求将所有输入参数的指针引用传递给服务操作。 适用于 Go 的 AWS SDK v2 无需尽可能将输入值作为指针传递，从而简化了大多数服务的体验。此更改意味着许多服务客户端操作不再要求您的应用程序传递以下类型的指针引用：`uint8`、`uint16`、`uint32`、`int8`、`int16`、`int32`、`float32`、`float64`、`bool`。同样，切片和映射元素类型已相应更新，以反映其元素是否必须作为指针引用传递。

 [aws](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws) 程序包中包含用于为 Go 内置类型创建指针的帮助程序函数，应使用这些帮助程序更轻松地为这些 Go 类型创建指针类型。同样，还提供了帮助程序方法，用于安全地取消引用这些类型的指针值。例如，[aws.String](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#String) 函数从 `string` 转换为 `*string`。相反，a [ws。 ToString](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#ToString)从 `*string` ⇒ 转换`string`。将应用程序从 适用于 Go 的 AWS SDK v1 升级到 v2 时，必须迁移帮助程序的使用情况，以便从指针类型转换为非指针变体。例如，aw [s。 StringValue](https://docs.aws.amazon.com/sdk-for-go/api/aws/#StringValue)必须更新为`aws.ToString`。

### 错误类型
<a name="errors-types"></a>

 充分 适用于 Go 的 AWS SDK 利用了 [Go 1.13 中引入的](https://go.dev/blog/go1.13-errors)错误包装功能。为错误响应建模的服务在其客户端的 `types` 程序包中生成了相应的类型，这些类型可用于测试客户端操作错误是否由其中一种类型引起。例如，如果尝试检索不存在的对象键，Amazon S3 `GetObject` 操作可能会返回 `NoSuchKey` 错误。[你可以使用 [errors.as](https://pkg.go.dev/errors#As) 来测试返回的操作错误是否为类型。 NoSuchKey](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#NoSuchKey)错误。如果服务没有针对特定类型的错误进行建模，则可以使用[铁匠铺。 APIError](https://pkg.go.dev/github.com/aws/smithy-go#APIError)用于检查服务返回的错误代码和消息的接口类型。此功能取代[了 awserr.Error](https://docs.aws.amazon.com/sdk-for-go/api/aws/awserr//#Error) 和 v1 中的其他 [awserr](https://docs.aws.amazon.com/sdk-for-go/api/aws/awserr/) 功能。 适用于 Go 的 AWS SDK 有关处理错误的更多详细信息，请参阅[处理适用于 Go 的 AWS SDK V2 中的错误](handle-errors.md)。

#### 示例
<a name="example-6"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/awserr"
import "github.com/aws/aws-sdk-go/service/s3"

// ...

client := s3.New(sess)

output, err := s3.GetObject(&s3.GetObjectInput{
    // input parameters
})
if err != nil {
    if awsErr, ok := err.(awserr.Error); ok {
        if awsErr.Code() == "NoSuchKey" {
            // handle NoSuchKey
        } else {
            // handle other codes
        }
        return
    }
    // handle a error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/aws-sdk-go-v2/service/s3/types"
import "github.com/aws/smithy-go"

// ...

client := s3.NewFromConfig(cfg)

output, err := client.GetObject(context.TODO(), &s3.GetObjectInput{
    // input parameters
})
if err != nil {
    var nsk *types.NoSuchKey
    if errors.As(err, &nsk) {
        // handle NoSuchKey error
        return
    }
    var apiErr smithy.APIError
    if errors.As(err, &apiErr) {
        code := apiErr.ErrorCode()
        message := apiErr.ErrorMessage()
        // handle error code
        return
    }
    // handle error
    return
}
```

### 分页器
<a name="paginators"></a>

 不再将服务操作分页器作为服务客户端上的方法进行调用。要将分页器用于某项操作，必须使用分页器构造函数方法之一为操作构造分页器。[例如，要在 Amazon S3 `ListObjectsV2` 操作上使用分页功能，您必须使用 s3 构造其分页器。 NewListObjectsV2Paginator](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#NewListObjectsV2Paginator)。此构造函数返回一个 [ListObjectsV2Paginator](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#ListObjectsV2Paginator)，它提供了方法`HasMorePages`，`NextPage`用于确定是否还有更多页面需要检索，并分别调用该操作来检索下一页。有关使用 SDK 分页器的更多详细信息，请访问[使用操作分页器](using.md#using-operation-paginators)。

 让我们来看一个如何从 适用于 Go 的 AWS SDK v1 分页器迁移到 v2 等效分页器的示例。 适用于 Go 的 AWS SDK 

#### 示例
<a name="example-7"></a>

```
// V1

import "fmt"
import "github.com/aws/aws-sdk-go/service/s3"

// ...

client := s3.New(sess)

params := &s3.ListObjectsV2Input{
    // input parameters
}

totalObjects := 0
err := client.ListObjectsV2Pages(params, func(output *s3.ListObjectsV2Output, lastPage bool) bool {
    totalObjects += len(output.Contents)
    return !lastPage
})
if err != nil {
    // handle error
}
fmt.Println("total objects:", totalObjects)
```

```
// V2

import "context"
import "fmt"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

client := s3.NewFromConfig(cfg)

params := &s3.ListObjectsV2Input{
    // input parameters
}

totalObjects := 0
paginator := s3.NewListObjectsV2Paginator(client, params)
for paginator.HasMorePages() {
    output, err := paginator.NextPage(context.TODO())
    if err != nil {
        // handle error
    }
    totalObjects += len(output.Contents)
}
fmt.Println("total objects:", totalObjects)
```

### Waiter
<a name="waiters"></a>

 不再将服务操作 Waiter 作为服务客户端上的方法进行调用。要使用 Waiter，首先要构造所需的 Waiter 类型，然后调用 wait 方法。例如，要等待 Amazon S3 存储桶存在，您必须构造一个 `BucketExists` Waiter。使用 s [3。 NewBucketExistsWaiter](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#NewBucketExistsWaiter)用于创建 s [3 的构造函数。 BucketExistsWaiter](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#BucketExistsWaiter)。`s3.BucketExistsWaiter` 提供了 `Wait` 方法，可用于等待存储桶变为可用状态。

### 预签名请求
<a name="presigned-requests"></a>

 从技术上讲，V1 SD AWS K 支持对*任何* SDK 操作进行预签名，但是，这并不能准确表示服务级别实际支持的内容（实际上，大多数 AWS 服务操作都不支持预签名）。

 适用于 Go 的 AWS SDK 通过在服务包中公开特定于支持的预签名操作的特定`PresignClient` APIs 实现来解决这个问题。

 **注意：如果某项服务缺少对您在 SDK v1 中成功使用的操作的预签名支持，请通过[向上提交问题](https://github.com/aws/aws-sdk-go-v2/issues)来告知我们。 GitHub**

 使用 [Presign](https://docs.aws.amazon.com/sdk-for-go/api/aws/request/#Request.Presign)，[PresignRequest](https://docs.aws.amazon.com/sdk-for-go/api/aws/request/#Request.PresignRequest)必须转换为使用特定于服务的预签名客户端。

 以下示例说明如何迁移 S3 GetObject 请求的预签名：

```
// V1

import (
    "fmt"
    "time"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

func main() {
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    svc := s3.New(sess)
    req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("key"),
    })

    // pattern 1
    url1, err := req.Presign(20 * time.Minute)
    if err != nil {
        panic(err)
    }
    fmt.Println(url1)

    // pattern 2
    url2, header, err := req.PresignRequest(20 * time.Minute)
    if err != nil {
        panic(err)
    }
    fmt.Println(url2, header)
}
```

```
// V2

import (
    "context"
    "fmt"
    "time"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        panic(err)
    }

    svc := s3.NewPresignClient(s3.NewFromConfig(cfg))
    req, err := svc.PresignGetObject(context.Background(), &s3.GetObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("key"),
    }, func(o *s3.PresignOptions) {
        o.Expires = 20 * time.Minute
    })
    if err != nil {
        panic(err)
    }

    fmt.Println(req.Method, req.URL, req.SignedHeader)
}
```

## 请求自定义
<a name="request-customization"></a>

 已重新划分整体 [request.Request](https://docs.aws.amazon.com/sdk-for-go/api/aws/request/#Request) API。

### 操作输入/输出
<a name="operation-inputoutput"></a>

 不透明的 `Request` 字段 `Params` 和 `Data`（分别保存操作输入和输出结构）现在可在特定的中间件阶段作为输入/输出进行访问：

 必须将引用 `Request.Params` 和 `Request.Data` 的请求处理程序迁移到中间件。

#### 迁移 `Params`
<a name="migrating-params"></a>

```
// V1

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/request"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

func withPutObjectDefaultACL(acl string) request.Option {
    return func(r *request.Request) {
        in, ok := r.Params.(*s3.PutObjectInput)
        if !ok {
            return
        }

        if in.ACL == nil {
            in.ACL = aws.String(acl)
        }
        r.Params = in
    }
}

func main() {
    sess := session.Must(session.NewSession())
    sess.Handlers.Validate.PushBack(withPutObjectDefaultACL(s3.ObjectCannedACLBucketOwnerFullControl))

    // ...
}
```

```
// V2

import (
    "context"

    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/aws/aws-sdk-go-v2/service/s3/types"
    "github.com/aws/smithy-go/middleware"
    smithyhttp "github.com/aws/smithy-go/transport/http"
)

type withPutObjectDefaultACL struct {
    acl types.ObjectCannedACL
}

// implements middleware.InitializeMiddleware, which runs BEFORE a request has
// been serialized and can act on the operation input
var _ middleware.InitializeMiddleware = (*withPutObjectDefaultACL)(nil)

func (*withPutObjectDefaultACL) ID() string {
    return "withPutObjectDefaultACL"
}

func (m *withPutObjectDefaultACL) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (
    out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
    input, ok := in.Parameters.(*s3.PutObjectInput)
    if !ok {
        return next.HandleInitialize(ctx, in)
    }

    if len(input.ACL) == 0 {
        input.ACL = m.acl
    }
    in.Parameters = input
    return next.HandleInitialize(ctx, in)
}

// create a helper function to simplify instrumentation of our middleware
func WithPutObjectDefaultACL(acl types.ObjectCannedACL) func (*s3.Options) {
    return func(o *s3.Options) {
        o.APIOptions = append(o.APIOptions, func (s *middleware.Stack) error {
            return s.Initialize.Add(&withPutObjectDefaultACL{acl: acl}, middleware.After)
        })
    }
}

func main() {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        // ...
    }

    svc := s3.NewFromConfig(cfg, WithPutObjectDefaultACL(types.ObjectCannedACLBucketOwnerFullControl))
    // ...
}
```

#### 迁移 `Data`
<a name="migrating-data"></a>

```
// V1

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/request"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

func readPutObjectOutput(r *request.Request) {
        output, ok := r.Data.(*s3.PutObjectOutput)
        if !ok {
            return
        }

        // ...
    }
}

func main() {
    sess := session.Must(session.NewSession())
    sess.Handlers.Unmarshal.PushBack(readPutObjectOutput)

    svc := s3.New(sess)
    // ...
}
```

```
// V2

import (
    "context"

    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/aws/smithy-go/middleware"
    smithyhttp "github.com/aws/smithy-go/transport/http"
)

type readPutObjectOutput struct{}

var _ middleware.DeserializeMiddleware = (*readPutObjectOutput)(nil)

func (*readPutObjectOutput) ID() string {
    return "readPutObjectOutput"
}

func (*readPutObjectOutput) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
    out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
) {
    out, metadata, err = next.HandleDeserialize(ctx, in)
    if err != nil {
        // ...
    }

    output, ok := in.Parameters.(*s3.PutObjectOutput)
    if !ok {
        return out, metadata, err
    }

    // inspect output...

    return out, metadata, err
}

func WithReadPutObjectOutput(o *s3.Options) {
    o.APIOptions = append(o.APIOptions, func (s *middleware.Stack) error {
        return s.Initialize.Add(&withReadPutObjectOutput{}, middleware.Before)
    })
}

func main() {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        // ...
    }

    svc := s3.NewFromConfig(cfg, WithReadPutObjectOutput)
    // ...
}
```

### HTTP 请求/响应
<a name="http-requestresponse"></a>

 `Request` 中的 `HTTPRequest` 和 `HTTPResponse` 字段现已在特定的中间件阶段提供。由于中间件与传输无关，因此您必须对中间件输入或输出执行类型断言，以显示底层 HTTP 请求或响应。

 必须将引用 `Request.HTTPRequest` 和 `Request.HTTPResponse` 的请求处理程序迁移到中间件。

#### 迁移 `HTTPRequest`
<a name="migrating-httprequest"></a>

```
// V1

import (
    "github.com/aws/aws-sdk-go/aws/request"
    "github.com/aws/aws-sdk-go/aws/session"
)

func withHeader(header, val string) request.Option {
    return func(r *request.Request) {
        request.HTTPRequest.Header.Set(header, val)
    }
}

func main() {
    sess := session.Must(session.NewSession())
    sess.Handlers.Build.PushBack(withHeader("x-user-header", "..."))

    svc := s3.New(sess)
    // ...
}
```

```
// V2

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/aws/smithy-go/middleware"
    smithyhttp "github.com/aws/smithy-go/transport/http"
)

type withHeader struct {
    header, val string
}

// implements middleware.BuildMiddleware, which runs AFTER a request has been
// serialized and can operate on the transport request
var _ middleware.BuildMiddleware = (*withHeader)(nil)

func (*withHeader) ID() string {
    return "withHeader"
}

func (m *withHeader) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
    out middleware.BuildOutput, metadata middleware.Metadata, err error,
) {
    req, ok := in.Request.(*smithyhttp.Request)
    if !ok {
        return out, metadata, fmt.Errorf("unrecognized transport type %T", in.Request)
    }

    req.Header.Set(m.header, m.val)
    return next.HandleBuild(ctx, in)
}

func WithHeader(header, val string) func (*s3.Options) {
    return func(o *s3.Options) {
        o.APIOptions = append(o.APIOptions, func (s *middleware.Stack) error {
            return s.Build.Add(&withHeader{
                header: header,
                val: val,
            }, middleware.After)
        })
    }
}

func main() {
    cfg, err := config.LoadDefaultConfig(context.Background())
    if err != nil {
        // ...
    }

    svc := s3.NewFromConfig(cfg, WithHeader("x-user-header", "..."))
    // ...
}
```

### 处理程序阶段
<a name="handler-phases"></a>

 SDK v2 中间件阶段是 v1 处理程序阶段的后继阶段。

 下表提供了 v1 处理程序阶段与 v2 中间件堆栈中等效位置的粗略映射：


|  v1 处理程序名称  |  v2 中间件阶段  | 
| --- | --- | 
|  验证  |  初始化  | 
|  构建  |  序列化  | 
|  签名  |  最终确定  | 
|  发送  |  n/a (1)  | 
|  ValidateResponse  |  反序列化  | 
|  解组  |  反序列化  | 
|  UnmarshalMetadata  |  反序列化  | 
|  UnmarshalError  |  反序列化  | 
|  重试  |  最终确定，在 "Retry" 中间件之后（2）  | 
|  AfterRetry  |  最终确定，在 "Retry" 中间件之前，在 next.HandleFinalize() 之后（2、3）  | 
|  CompleteAttempt  |  最终确定，步骤结束  | 
|  完成  |  初始化，步骤开始，next.HandleInitialize() 之后（3）  | 

 （1）v1 中的 `Send` 阶段实际上是 v2 中包装的 HTTP 客户端往返行程。此行为由客户端选项上的 `HTTPClient` 字段控制。

 （2）“最终确定”步骤中 `"Retry"` 中间件之后的任何中间件都将是重试循环的一部分。

 （3）操作时的中间件“堆栈”内置在重复装饰的处理程序函数中。每个处理程序都负责调用链中的下一个处理程序。这实际上意味着中间件步骤也可以在其下一步骤调用之后执行操作。

 例如，对于堆栈顶部的“初始化”步骤，这意味着在调用下一个处理程序后执行操作的初始化中间件实际上是在请求结束时才运行：

```
// V2

import (
    "context"

    "github.com/aws/smithy-go/middleware"
)

type onComplete struct{}

var _ middleware.InitializeMiddleware = (*onComplete)(nil)

func (*onComplete) ID() string {
    return "onComplete"
}

func (*onComplete) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (
    out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
    out, metadata, err = next.HandleInitialize(ctx, in)

    // the entire operation was invoked above - the deserialized response is
    // available opaquely in out.Result, run post-op actions here...

    return out, metadata, err
}
```

## 功能
<a name="features"></a>

### Amazon EC2 实例元数据服务
<a name="ec2-instance-metadata-service"></a>

 适用于 Go 的 AWS SDK 提供了亚马逊 EC2 实例元数据服务 (IMDS) 客户端，在亚马逊实例上执行应用程序时，您可以使用该客户端查询本地 IMDS。 EC2 IMDS 客户端是一个单独的 Go 模块，您可以使用以下命令将其添加到应用程序中 

```
go get github.com/aws/aws-sdk-go-v2/feature/ec2/imds
```

 客户端构造函数和方法操作已更新，以匹配其他 SDK 服务客户端的设计。

#### 示例
<a name="example-8"></a>

```
// V1

import "github.com/aws/aws-sdk-go/aws/ec2metadata"

// ...

client := ec2metadata.New(sess)

region, err := client.Region()
if err != nil {
    // handle error
}
```

```
// V2

import "context"
import "github.com/aws/aws-sdk-go-v2/feature/ec2/imds"

// ...

client := imds.NewFromConfig(cfg)

region, err := client.GetRegion(context.TODO())
if err != nil {
    // handle error
}
```

### Amazon S3 Transfer Manager
<a name="s3-transfer-manager"></a>

 Amazon S3 Transfer Manager 可用于同时管理对象的上传和下载。此程序包位于服务客户端导入路径之外的 Go 模块中。可以使用 `go get github.com/aws/aws-sdk-go-v2/feature/s3/manager` 来检索此模块。

 [s3。 NewUploader](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#NewUploader)和 [s3。 NewUploaderWithClient](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#NewUploaderWithClient)已被构造函数方法[管理器所取代。 NewUploader](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#)用于创建上传管理器客户端。

 [s3。 NewDownloader](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#NewDownloader)和 [s3。 NewDownloaderWithClient](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/#NewDownloaderWithClient)已被单个构造函数方法[管理器所取代。 NewDownloader](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#NewDownloader)用于创建下载管理器客户端。

### Amazon CloudFront 签名工具
<a name="cflong-signing-utilities"></a>

 在服务客户端导入路径之外的 Go 模块中 适用于 Go 的 AWS SDK 提供 Amazon CloudFront 签名实用程序。可以使用 `go get` 来检索此模块。

```
go get github.com/aws/aws-sdk-go-v2/feature/cloudfront/sign
```

### Amazon S3 加密客户端
<a name="s3-encryption-client"></a>

 首先 适用于 Go 的 AWS SDK，Amazon S3 加密客户端是[AWS 加密工具](https://docs.aws.amazon.com/aws-crypto-tools)下的独立模块。适用于 Go 的 S3 加密客户端 3.x 的最新版本现已在上[GitHub](https://github.com/aws/amazon-s3-encryption-client-go)线。可以使用 `go get` 来检索此模块：

```
go get github.com/aws/amazon-s3-encryption-client-go/v3
```

 单独的`EncryptionClient`（[v1](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/#EncryptionClient)、[v2](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/#EncryptionClientV2)）和`DecryptionClient`（[v1、v](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/#DecryptionClient) [2） APIs 已被单个客户端 S3 EncryptionClient V](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/#DecryptionClientV2) [3](https://pkg.go.dev/github.com/aws/amazon-s3-encryption-client-go/v3/client#S3EncryptionClientV3) 所取代，该客户端同时提供加密和解密功能。

 像中的其他服务客户一样 适用于 Go 的 AWS SDK，该操作 APIs 已被压缩：
+  `GetObject``GetObjectRequest`、和`GetObjectWithContext`解密被替换 APIs 为。[GetObject](https://pkg.go.dev/github.com/aws/amazon-s3-encryption-client-go/v3/client#S3EncryptionClientV3.GetObject)
+  `PutObject``PutObjectRequest`、和`PutObjectWithContext`加密 APIs 被替换为[PutObject](https://pkg.go.dev/github.com/aws/amazon-s3-encryption-client-go/v3/client#S3EncryptionClientV3.PutObject)。

 要了解如何迁移到加密客户端的 3.x 主要版本，请参阅[本指南](https://docs.aws.amazon.com/amazon-s3-encryption-client/latest/developerguide/go-v3-migration.html)。

## 服务自定义更改
<a name="service-customizations-changes"></a>

### Amazon S3
<a name="s3"></a>

 从 适用于 Go 的 AWS SDK v1 迁移到 v2 时，需要注意的一个重要变化涉及使用客户提供的密钥 (SSE-C) 处理`SSECustomerKey`用于服务器端加密的内容。在 适用于 Go 的 AWS SDK v1 中，`SSECustomerKey`到 Base64 的编码由软件开发工具包内部处理。在 SDK v2 中，这种自动编码功能已被删除，现在需要手动将 `SSECustomerKey` 编码为 Base64，然后再将其传递给 SDK。

 示例调整：

```
// V1

import (
  "context"
  "encoding/base64"
  "github.com/aws/aws-sdk-go-v2/config"
  "github.com/aws/aws-sdk-go-v2/service/s3"
)
// ... more code

plainTextKey := "12345678901234567890123456789012" // 32 bytes in length

// calculate md5..

_, err = client.PutObjectWithContext(context.Background(), &s3.PutObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("your-object-key"),
    Body:                 strings.NewReader("hello-world"),
    SSECustomerKey:       &plainTextKey,
    SSECustomerKeyMD5:    &base64Md5,
    SSECustomerAlgorithm: aws.String("AES256"),
})

// ... more code
```

```
// V2

import (
  "github.com/aws/aws-sdk-go/aws"
  "github.com/aws/aws-sdk-go/aws/session"
  "github.com/aws/aws-sdk-go/service/s3"
)

// ... more code

plainTextKey := "12345678901234567890123456789012" // 32 bytes in length
base64EncodedKey := base64.StdEncoding.EncodeToString([]byte(plainTextKey))

// calculate md5..

_, err = client.PutObject(context.Background(), &s3.PutObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("your-object-key"),
    Body:                 strings.NewReader("hello-world"),
    SSECustomerKey:       &base64EncodedKey,
    SSECustomerKeyMD5:    &base64Md5,
    SSECustomerAlgorithm: aws.String("AES256"),
})

// ... more code
```