

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

# 設定用戶端端點
<a name="configure-endpoints"></a>

**警告**  
 端點解析是進階 SDK 主題。透過變更這些設定，您可能會破壞程式碼。預設設定應適用於生產環境中的大多數使用者。

 適用於 Go 的 AWS SDK 可讓您設定要用於服務的自訂端點。在大多數情況下，預設組態就足夠了。設定自訂端點允許其他行為，例如使用服務的發行前版本。

## 自訂
<a name="customization"></a>

 開發套件中有兩個端點解析組態的「版本」。
+  v2，已於 202Q3發行，透過下列方式設定：
  +  `EndpointResolverV2` 
  +  `BaseEndpoint` 
+  v1，與 SDK 一起發行，透過下列方式設定：
  +  `EndpointResolver` 

 我們建議 v1 端點解析的使用者遷移至 v2，以取得較新的端點相關服務功能的存取權。

## V2：`EndpointResolverV2`\$1 `BaseEndpoint`
<a name="v2-endpointresolverv2--baseendpoint"></a>

 在解析 v2 中， `EndpointResolverV2`是端點解析發生的最終機制。針對您在 SDK 中提出的每個請求，系統會呼叫解析程式`ResolveEndpoint`的方法，做為工作流程的一部分。提出請求時，解析程式`Endpoint`傳回的 主機名稱會**依原樣**使用 （不過，操作序列化程式仍然可以附加到 HTTP 路徑）。

 解決方案 v2 包含額外的用戶端層級組態 `BaseEndpoint`，用於為您的服務執行個體指定 "base" 主機名稱。此處設定的值並非確定性 - 最終會在最終解析發生`EndpointResolverV2`時，以參數形式傳遞給用戶端的 （如需`EndpointResolverV2`參數的詳細資訊，請參閱 )。然後，解析程式實作有機會檢查並可能修改該值，以判斷最終端點。

 例如，如果您使用已指定 的用戶端對指定的儲存貯體執行 S3 `GetObject`請求`BaseEndpoint`，預設解析程式會在與虛擬主機相容 （假設您尚未在用戶端組態中停用虛擬託管） 時，將儲存貯體注入主機名稱。

 實際上， `BaseEndpoint` 最有可能用來將用戶端指向服務的開發或預覽執行個體。

### `EndpointResolverV2` 參數
<a name="endpointresolverv2-parameters"></a>

 每個服務都會接受一組特定的輸入，這些輸入會傳遞至其解析度函數，並在每個服務套件中定義為 `EndpointParameters`。

 每個服務都包含下列基本參數，用於促進 內的一般端點解析 AWS：


|  name  |  type  |  description  | 
| --- | --- | --- | 
|  Region  |  string  |  用戶端 AWS 的區域  | 
|  Endpoint  |  string  |  在用戶端組態BaseEndpoint中為 設定的值  | 
|  UseFips  |  bool  |  是否在用戶端組態中啟用 FIPS 端點  | 
|  UseDualStack  |  bool  |  是否在用戶端組態中啟用雙堆疊端點  | 

 服務可以指定解析所需的其他參數。例如，S3 的 `EndpointParameters`包含儲存貯體名稱，以及數個 S3-specific功能設定，例如是否啟用虛擬主機定址。

 如果您正在實作自己的 `EndpointResolverV2`，則永遠不需要建構自己的 執行個體`EndpointParameters`。開發套件會取得每個請求的值，並將其傳遞給您的實作。

### 有關 Amazon S3 的備註
<a name="a-note-about-amazon-s3"></a>

 Amazon S3 是一種複雜的服務，其許多功能透過複雜的端點自訂建模，例如儲存貯體虛擬託管、S3 MRAP 等。

 因此，建議您不要取代 S3 用戶端中的`EndpointResolverV2`實作。如果您需要擴展其解決行為，也許透過傳送請求到具有其他端點考量的本機開發堆疊，我們建議包裝預設實作，以便將其委派回預設值作為備用 （如以下範例所示）。

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

#### 搭配 `BaseEndpoint`
<a name="with-baseendpoint"></a>

 下列程式碼片段顯示如何將 S3 用戶端指向服務的本機執行個體，在此範例中，該執行個體託管在連接埠 8080 的迴路裝置上。

```
client := s3.NewFromConfig(cfg, func (o *svc.Options) {
    o.BaseEndpoint = aws.String("https://localhost:8080/")
})
```

#### 搭配 `EndpointResolverV2`
<a name="with-endpointresolverv2"></a>

 下列程式碼片段說明如何使用 將自訂行為注入 S3 的端點解析`EndpointResolverV2`。

```
import (
    "context"
    "net/url"

    "github.com/aws/aws-sdk-go-v2/service/s3"
    smithyendpoints "github.com/aws/smithy-go/endpoints"
)

type resolverV2 struct {
    // you could inject additional application context here as well
}

func (*resolverV2) ResolveEndpoint(ctx context.Context, params s3.EndpointParameters) (
        smithyendpoints.Endpoint, error,
    ) {
    if /* input params or caller context indicate we must route somewhere */ {
        u, err := url.Parse("https://custom.service.endpoint/")
        if err != nil {
            return smithyendpoints.Endpoint{}, err
        }
        return smithyendpoints.Endpoint{
            URI: *u,
        }, nil
    }

    // delegate back to the default v2 resolver otherwise
    return s3.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params)
}

func main() {
    // load config...

    client := s3.NewFromConfig(cfg, func (o *s3.Options) {
        o.EndpointResolverV2 = &resolverV2{
            // ...
        }
    })
}
```

#### 使用兩者
<a name="with-both"></a>

 下列範例程式示範 `BaseEndpoint`和 之間的互動`EndpointResolverV2`。**這是進階使用案例：**

```
import (
    "context"
    "fmt"
    "log"
    "net/url"

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

type resolverV2 struct {}

func (*resolverV2) ResolveEndpoint(ctx context.Context, params s3.EndpointParameters) (
        smithyendpoints.Endpoint, error,
    ) {
    // s3.Options.BaseEndpoint is accessible here:
    fmt.Printf("The endpoint provided in config is %s\n", *params.Endpoint)

    // fallback to default
    return s3.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params)
}

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

    client := s3.NewFromConfig(cfg, func (o *s3.Options) {
        o.BaseEndpoint = aws.String("https://endpoint.dev/")
        o.EndpointResolverV2 = &resolverV2{}
    })

    // ignore the output, this is just for demonstration
    client.ListBuckets(context.Background(), nil)
}
```

 執行時，上述程式會輸出下列項目：

```
The endpoint provided in config is https://endpoint.dev/
```

## V1： `EndpointResolver`
<a name="v1-endpointresolver"></a>

**警告**  
 端點解析 v1 會保留為回溯相容性，並與端點解析 v2 中的現代行為隔離。只有在呼叫者設定 `EndpointResolver` 欄位時，才會使用它。  
 使用 v1 很可能會阻止您存取 v2 解析度發行時或之後推出的端點相關服務功能。如需如何升級的說明，請參閱「遷移」。

 [EndpointResolver](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#EndpointResolver) 可設定為為服務用戶端提供自訂端點解析邏輯。您可以使用自訂端點解析程式，為所有端點或僅特定區域端點覆寫服務的端點解析邏輯。如果自訂解析程式不希望解析請求的端點，自訂端點解析程式可以觸發服務的端點解析邏輯進行備用。[EndpointResolverWithOptionsFunc](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#EndpointResolverWithOptionsFunc) 可用來輕鬆包裝函數以滿足`EndpointResolverWithOptions`界面。

 `EndpointResolver` 您可以透過將包裝有 [WithEndpointResolverWithOptions](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#WithEndpointResolverWithOptions) 的解析程式傳遞至 [LoadDefaultConfig](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#LoadDefaultConfig) 來輕鬆設定 ，允許在載入登入資料時覆寫端點，以及`aws.Config`使用自訂端點解析程式設定結果。

 端點解析程式以字串形式提供服務和區域，允許解析程式動態驅動其行為。每個服務用戶端套件都有匯出的`ServiceID`常數，可用來判斷哪個服務用戶端叫用您的端點解析程式。

 端點解析程式可以使用 [EndpointNotFoundError](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#EndpointNotFoundError) sentinel 錯誤值來觸發服務用戶端預設解析邏輯的備用解析。這可讓您選擇無縫覆寫一或多個端點，而無需處理備用邏輯。

 如果您的端點解析程式實作傳回 以外的錯誤`EndpointNotFoundError`，端點解析會停止，而服務操作會傳回錯誤到您的應用程式。

### 範例
<a name="examples-1"></a>

#### 使用備用
<a name="with-fallback"></a>

 下列程式碼片段顯示如何使用其他端點的備用行為，覆寫 DynamoDB 的單一服務端點：

```
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
        }, nil
    }
    // returning EndpointNotFoundError will allow the service to fallback to it's default resolution
    return aws.Endpoint{}, &aws.EndpointNotFoundError{}
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
```

#### 無備用
<a name="without-fallback"></a>

 下列程式碼片段顯示如何覆寫 DynamoDB 的單一服務端點，而沒有其他端點的備用行為：

```
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
        }, nil
    }
    return aws.Endpoint{}, fmt.Errorf("unknown endpoint requested")
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
```

### 不可變端點
<a name="immutable-endpoints"></a>

**警告**  
 將端點設定為不可變可能會阻止某些服務用戶端功能正常運作，並可能導致未定義的行為。將端點定義為不可變時，應小心。

 有些服務用戶端，例如 Amazon S3，可能會修改解析程式針對特定服務操作傳回的端點。例如，Amazon S3 會自動透過變更已解析的端點來處理[虛擬儲存貯體定址](https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html)。您可以將 [HostnameImmutable](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Endpoint.HostnameImmutable) 設定為 ，以防止 SDK 變更您的自訂端點`true`。例如：

```
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
            HostnameImmutable: true,
        }, nil
    }
    return aws.Endpoint{}, fmt.Errorf("unknown endpoint requested")
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
```

## 移轉
<a name="migration"></a>

 從 v1 遷移到 v2 端點解析時，適用下列一般原則：
+  將 [HostnameImmutable](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Endpoint.HostnameImmutable) 設定為 `false` 的[端點](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws#Endpoint)傳回大約等同於`BaseEndpoint`將 設定為 v1 最初傳回的 URL，並保留`EndpointResolverV2`為預設值。
+  將 HostnameImmutable 設定為 `true` 的端點傳回大約等同於實作 `EndpointResolverV2`，這會傳回 v1 中最初傳回的 URL。
  +  主要例外是針對具有模型化端點字首的操作。這會進一步記下。

 以下提供這些案例的範例。

**警告**  
 V1 不可變端點和 V2 解析度在行為中不相等。例如，S3 Object Lambda 等自訂功能的簽署覆寫仍會針對透過 v1 程式碼傳回的不可變端點進行設定，但 v2 不會進行相同的操作。

### 主機字首注意事項
<a name="note-on-host-prefixes"></a>

 有些操作使用主機字首建模，以附加到已解析的端點。此行為必須與 ResolveEndpointV2 的輸出一起運作，因此主機字首仍會套用至該結果。

 您可以套用中介軟體來手動停用端點主機字首，請參閱範例一節。

### 範例
<a name="examples-2"></a>

#### 可變端點
<a name="mutable-endpoint"></a>

 下列程式碼範例示範如何遷移基本 v1 端點解析程式，以傳回可修改的端點：

```
// v1
client := svc.NewFromConfig(cfg, func (o *svc.Options) {
    o.EndpointResolver = svc.EndpointResolverFromURL("https://custom.endpoint.api/")
})

// v2
client := svc.NewFromConfig(cfg, func (o *svc.Options) {
    // the value of BaseEndpoint is passed to the default EndpointResolverV2
    // implementation, which will handle routing for features such as S3 accelerate,
    // MRAP, etc.
    o.BaseEndpoint = aws.String("https://custom.endpoint.api/")
})
```

#### 不可變端點
<a name="immutable-endpoint"></a>

```
// v1
client := svc.NewFromConfig(cfg, func (o *svc.Options) {
    o.EndpointResolver = svc.EndpointResolverFromURL("https://custom.endpoint.api/", func (e *aws.Endpoint) {
        e.HostnameImmutable = true
    })
})

// v2
import (
    smithyendpoints "github.com/aws/smithy-go/endpoints"
)

type staticResolver struct {}

func (*staticResolver) ResolveEndpoint(ctx context.Context, params svc.EndpointParameters) (
        smithyendpoints.Endpoint, error,
    ) {
    // This value will be used as-is when making the request.
    u, err := url.Parse("https://custom.endpoint.api/")
    if err != nil {
        return smithyendpoints.Endpoint{}, err
    }
    return smithyendpoints.Endpoint{
        URI: *u,
    }, nil
}

client := svc.NewFromConfig(cfg, func (o *svc.Options) {
    o.EndpointResolverV2 = &staticResolver{}
})
```

#### 停用主機字首
<a name="disable-host-prefix"></a>

```
import (
    "context"
    "fmt"
    "net/url"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/<service>"
    smithyendpoints "github.com/aws/smithy-go/endpoints"
    "github.com/aws/smithy-go/middleware"
    smithyhttp "github.com/aws/smithy-go/transport/http"
)

// disableEndpointPrefix applies the flag that will prevent any
// operation-specific host prefix from being applied
type disableEndpointPrefix struct{}

func (disableEndpointPrefix) ID() string { return "disableEndpointPrefix" }

func (disableEndpointPrefix) HandleInitialize(
    ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
) (middleware.InitializeOutput, middleware.Metadata, error) {
    ctx = smithyhttp.SetHostnameImmutable(ctx, true)
    return next.HandleInitialize(ctx, in)
}

func addDisableEndpointPrefix(o *<service>.Options) {
    o.APIOptions = append(o.APIOptions, (func(stack *middleware.Stack) error {
        return stack.Initialize.Add(disableEndpointPrefix{}, middleware.After)
    }))
}

type staticResolver struct{}

func (staticResolver) ResolveEndpoint(ctx context.Context, params <service>.EndpointParameters) (
    smithyendpoints.Endpoint, error,
) {
    u, err := url.Parse("https://custom.endpoint.api/")
    if err != nil {
        return smithyendpoints.Endpoint{}, err
    }

    return smithyendpoints.Endpoint{URI: *u}, nil
}


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

    svc := <service>.NewFromConfig(cfg, func(o *<service>.Options) {
        o.EndpointResolverV2 = staticResolver{}
    })

    _, err = svc.<Operation>(context.Background(), &<service>.<OperationInput>{ /* ... */ },
        addDisableEndpointPrefix)
    if err != nil {
        panic(err)
    }
}
```