기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
클라이언트 엔드포인트 구성
주의
엔드포인트 확인은 고급 SDK 주제입니다. 이러한 설정을 변경하면 코드가 손상될 위험이 있습니다. 기본 설정은 프로덕션 환경 내 대부분의 사용자에게 적용 가능해야 합니다.
AWS SDK for Go는 서비스에 사용할 사용자 지정 엔드포인트를 구성하는 기능을 제공합니다. 대부분의 경우는 기본 구성으로도 충분합니다. 사용자 지정 엔드포인트를 구성하면 서비스의 프리릴리스 버전 작업과 같은 추가 동작을 수행할 수 있습니다.
사용자 지정
SDK 내에는 엔드포인트 확인 구성의 두 가지 ‘버전’이 있습니다.
-
2023년 Q3에 릴리스되었으며 다음을 통해 구성된 v2:
-
EndpointResolverV2 -
BaseEndpoint
-
-
SDK와 함께 릴리스되었으며 다음을 통해 구성된 v1:
-
EndpointResolver
-
v1 엔드포인트 확인을 사용 중인 경우, 최신 엔드포인트 관련 서비스 기능에 액세스하려면 v2로 마이그레이션하는 것이 좋습니다.
V2: EndpointResolverV2 + BaseEndpoint
확인 v2에서 EndpointResolverV2는 엔드포인트 확인이 발생하는 최종 메커니즘입니다. 해석기의 ResolveEndpoint 메서드는 SDK에서 수행하는 모든 요청에서 워크플로의 일부로 간접 호출됩니다. 해석기가 반환한 Endpoint의 호스트 이름은 요청 시 그대로 사용됩니다(단, 작업 직렬화기는 여전히 HTTP 경로에 추가할 수 있음).
확인 v2에는 서비스 인스턴스의 ‘기본’ 호스트 이름을 지정하는 데 사용되는 추가 클라이언트 수준 구성인 BaseEndpoint가 포함되어 있습니다. 여기에 설정된 값은 확정적이지 않습니다. 최종 확인이 발생하면 궁극적으로 클라이언트의 EndpointResolverV2에 파라미터로 전달됩니다(EndpointResolverV2 파라미터에 대한 자세한 내용 참조). 그러면 해석기 구현을 통해 해당 값을 검사하고 잠재적으로 수정하여 최종 엔드포인트를 결정할 수 있습니다.
예를 들어 BaseEndpoint를 지정한 클라이언트를 사용하여 주어진 버킷에 대해 S3 GetObject 요청을 수행하는 경우, 가상 호스트와 호환되면(클라이언트 구성에서 가상 호스팅을 비활성화하지 않은 경우) 기본 해석기가 버킷을 호스트 이름에 주입합니다.
실제로 BaseEndpoint는 클라이언트가 서비스의 개발 또는 미리 보기 인스턴스를 가리키는 데 사용될 가능성이 높습니다.
EndpointResolverV2 파라미터
각 서비스는 각 서비스 패키지에 EndpointParameters로 정의된 확인 함수로 전달되는 특정 입력 세트를 가져옵니다.
모든 서비스에는 AWS 내에서 일반적인 엔드포인트 확인을 용이하게 하는 데 사용되는 다음의 기본 파라미터가 포함되어 있습니다.
| name | 유형 | 설명 |
|---|---|---|
Region
|
string
|
클라이언트의 AWS 리전 |
Endpoint
|
string
|
클라이언트 구성에서 BaseEndpoint에 대해 설정된 값 |
UseFips
|
bool
|
클라이언트 구성에서 FIPS 엔드포인트가 활성화되었는지 여부 |
UseDualStack
|
bool
|
클라이언트 구성에서 듀얼 스택 엔드포인트가 활성화되었는지 여부 |
서비스는 해결에 필요한 추가 파라미터를 지정할 수 있습니다. 예를 들어 S3의 EndpointParameters에는 버킷 이름 외에도 가상 호스트 주소 지정 활성화 여부와 같은 여러 S3 전용 기능 설정이 포함됩니다.
자체 EndpointResolverV2를 구현하는 경우 자체 EndpointParameters 인스턴스를 구성할 필요가 없습니다. SDK는 요청당 값을 소싱하여 구현에 전달합니다.
Amazon S3에 대한 참고 사항
Amazon S3는 버킷 가상 호스팅, S3 MRAP 등과 같은 복잡한 엔드포인트 사용자 지정을 통해 모델링된 많은 기능을 갖춘 복잡한 서비스입니다.
따라서 S3 클라이언트에서 EndpointResolverV2 구현을 교체하지 않는 것이 좋습니다. 추가적인 엔드포인트 고려 사항과 함께 로컬 개발 스택에 요청을 보내는 등 해결 동작을 확장해야 하는 경우, 기본 구현을 래핑하여 폴백의 형태로 기본값으로 위임하는 것이 좋습니다(아래 예시 참조).
예시
BaseEndpoint 포함
다음 코드 조각은 S3 클라이언트가 서비스의 로컬 인스턴스를 가리키도록 하는 방법을 보여줍니다. 이 예제에서는 포트 8080의 루프백 디바이스에서 호스팅됩니다.
client := s3.NewFromConfig(cfg, func (o *svc.Options) { o.BaseEndpoint = aws.String("https://localhost:8080/") })
EndpointResolverV2 포함
다음 코드 조각은 EndpointResolverV2를 사용하여 S3의 엔드포인트 확인에 사용자 지정 동작을 주입하는 방법을 보여줍니다.
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{ // ... } }) }
둘 다 포함
다음 샘플 프로그램은 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
주의
엔드포인트 확인 v1은 이전 버전과의 호환성을 위해 유지되며 엔드포인트 확인 v2의 최신 동작과 분리됩니다. 호출자가 EndpointResolver 필드를 설정한 경우에만 사용됩니다.
v1을 사용하면 v2 확인 릴리스 시 또는 릴리스 후에 도입된 엔드포인트 관련 서비스 기능에 액세스하지 못할 가능성이 높습니다. 업그레이드 방법에 대한 지침은 ‘마이그레이션’을 참조하세요.
서비스 클라이언트에 대한 사용자 지정 엔드포인트 확인 로직을 제공하도록 EndpointResolverEndpointResolverWithOptions 인터페이스를 충족하는 데 필요한 함수를 쉽게 래핑할 수 있습니다.
WithEndpointResolverWithOptionsEndpointResolver를 쉽게 구성할 수 있으므로 자격 증명을 로드할 때 엔드포인트를 재정의하고 사용자 지정 엔드포인트 해석기로 결과 aws.Config를 구성할 수 있습니다.
엔드포인트 해석기에는 서비스와 리전이 문자열로 제공되므로 해석기가 동적으로 동작을 구동할 수 있습니다. 각 서비스 클라이언트 패키지에는 엔드포인트 해석기를 간접적으로 호출하는 서비스 클라이언트를 결정하는 데 사용할 수 있는 내보낸 ServiceID 상수가 있습니다.
엔드포인트 해석기는 EndpointNotFoundError
엔드포인트 해석기 구현에서 EndpointNotFoundError 이외의 오류가 반환되면 엔드포인트 확인이 중지되고 서비스 작업은 애플리케이션에 오류를 반환합니다.
예시
폴백 포함
다음 코드 조각은 다른 엔드포인트에 대한 폴백 동작을 사용하여 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))
폴백 없음
다음 코드 조각은 다른 엔드포인트에 대한 폴백 동작을 사용하지 않고 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))
변경 불가능한 엔드포인트
주의
엔드포인트를 변경 불가능으로 설정하면 일부 서비스 클라이언트 기능이 올바르게 작동하지 않게 되어 정의되지 않은 동작이 발생할 수 있습니다. 엔드포인트를 변경 불가능으로 정의할 때는 주의해야 합니다.
Amazon S3와 같은 일부 서비스 클라이언트는 특정 서비스 작업을 위해 해석기가 반환한 엔드포인트를 수정할 수 있습니다. 예를 들어 Amazon S3는 확인된 엔드포인트를 변경하여 가상 버킷 주소 지정을 자동으로 처리합니다. HostnameImmutabletrue로 설정하여 SDK가 사용자 지정 엔드포인트를 변경하지 못하도록 할 수 있습니다. 예:
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))
마이그레이션
엔드포인트 확인의 v1에서 v2로 마이그레이션할 때 다음과 같은 일반 원칙이 적용됩니다.
-
HostnameImmutable
이 false로 설정된 엔드포인트를 반환하는 것은 BaseEndpoint를 v1에서 원래 반환된 URL로 설정하고EndpointResolverV2를 기본값으로 두는 것과 거의 동일합니다. -
HostnameImmutable이
true로 설정된 엔드포인트를 반환하는 것은 v1에서 원래 반환된 URL을 반환하는EndpointResolverV2를 구현하는 것과 거의 동일합니다.-
기본 예외는 모델링된 엔드포인트 접두사가 있는 작업을 위한 것입니다. 이에 대한 자세한 내용은 아래에 나와 있습니다.
-
이러한 사례에 대한 예제는 아래에 제시되어 있습니다.
주의
V1 변경 불가능 엔드포인트와 V2 확인은 동작이 동일하지 않습니다. 예를 들어 S3 객체 Lambda와 같은 사용자 지정 기능에 대한 서명 재정의는 v1 코드를 통해 반환되는 변경 불가능 엔드포인트에 여전히 설정되지만 v2에 대해서는 동일하게 수행되지 않습니다.
호스트 접두사에 대한 참고 사항
일부 작업은 확인된 엔드포인트 앞에 추가할 호스트 접두사로 모델링됩니다. 이 동작은 ResolveEndpointV2의 출력과 함께 작동해야 하므로 호스트 접두사는 해당 결과에 계속 적용됩니다.
미들웨어를 적용하여 엔드포인트 호스트 접두사를 수동으로 비활성화할 수 있습니다. 예제 섹션을 참조하세요.
예시
변경 가능한 엔드포인트
다음 코드 샘플은 수정 가능한 엔드포인트를 반환하는 기본 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/") })
변경 불가능한 엔드포인트
// 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{} })
호스트 접두사 비활성화
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) } }