As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Configurar endpoints de cliente
Atenção
A resolução de endpoints é um tópico avançado do SDK. Ao alterar essas configurações, você corre o risco de quebrar seu código. As configurações padrão devem ser aplicáveis à maioria dos usuários em ambientes de produção.
O AWS SDK para Go permite configurar um endpoint personalizado para ser usado em um serviço. Na maioria dos casos, a configuração padrão é suficiente. A configuração de endpoints personalizados permite um comportamento adicional, como trabalhar com versões de pré-lançamento de um serviço.
Personalização
Há duas “versões” da configuração de resolução de endpoints no SDK.
-
v2, lançada no terceiro trimestre de 2023, configurada por meio de:
-
EndpointResolverV2 -
BaseEndpoint
-
-
v1, lançada junto com o SDK, configurada por meio de:
-
EndpointResolver
-
Recomendamos que os usuários da resolução de endpoint v1 migrem para a v2 para ter acesso aos novos recursos de serviço relacionados ao endpoint.
V2: EndpointResolverV2 + BaseEndpoint
Na resolução v2, EndpointResolverV2 é o mecanismo definitivo pelo qual ocorre a resolução do endpoint. O método ResolveEndpoint do resolvedor é invocado como parte do fluxo de trabalho para cada solicitação que você faz no SDK. O nome do host do Endpoint retornado pelo resolvedor é usado como está ao fazer a solicitação (no entanto, os serializadores de operação ainda podem ser anexados ao caminho HTTP).
A resolução v2 inclui uma configuração adicional no nível do cliente, BaseEndpoint, que é usada para especificar um nome de host “base” para a instância do serviço. O valor definido aqui não é definitivo. Em última análise, ele é passado como um parâmetro para o EndpointResolverV2 do cliente quando a resolução final ocorre (continue lendo para obter mais informações sobre os parâmetros EndpointResolverV2). A implementação do resolvedor então tem a oportunidade de inspecionar e possivelmente modificar esse valor para determinar o endpoint final.
Por exemplo, se você realizar uma solicitação GetObject do S3 em determinado bucket com um cliente em que você especificou um BaseEndpoint, o resolvedor padrão injetará o bucket no nome do host se ele for compatível com o host virtual (supondo que você não tenha desativado a hospedagem virtual na configuração do cliente).
Na prática, provavelmente BaseEndpoint será usado para direcionar o cliente a uma instância de desenvolvimento ou prévia de um serviço.
EndpointResolverV2Parâmetros do
Cada serviço usa um conjunto específico de entradas que são passadas para sua função de resolução, definida em cada pacote de serviços como EndpointParameters.
Cada serviço inclui os seguintes parâmetros básicos, que são usados para facilitar a resolução geral de endpoints na AWS:
| nome | type | description |
|---|---|---|
Region
|
string
|
A região da AWS do cliente |
Endpoint
|
string
|
O valor definido de BaseEndpoint na configuração do cliente |
UseFips
|
bool
|
Se os endpoints FIPS estão habilitados na configuração do cliente |
UseDualStack
|
bool
|
Se os endpoints de pilha dupla estão habilitados na configuração do cliente |
Os serviços podem especificar parâmetros adicionais necessários para a resolução. Por exemplo, EndpointParameters do S3 incluem o nome do bucket, bem como várias configurações de recursos específicos do S3, como se o endereçamento de host virtual está habilitado.
Se você estiver implementando seu próprio EndpointResolverV2, nunca será necessário construir sua própria instância de EndpointParameters. O SDK fornece os valores por solicitação e os transmite para sua implementação.
Uma observação sobre o Amazon S3
O Amazon S3 é um serviço complexo com muitos de seus recursos modelados por meio de personalizações complexas de endpoints, como hospedagem virtual de bucket, S3 MRAP e muito mais.
Por isso, recomendamos não substituir a implementação EndpointResolverV2 no cliente do S3. Se você precisar estender seu comportamento de resolução, talvez enviando solicitações a uma pilha de desenvolvimento local com considerações adicionais de endpoint, recomendamos encapsular a implementação padrão de forma que ela retorne ao padrão como alternativa (conforme mostrado nos exemplos abaixo).
Exemplos
Com BaseEndpoint
O trecho de código a seguir mostra como direcionar o cliente do S3 para uma instância local de um serviço, que neste exemplo está hospedada no dispositivo de loopback na porta 8080.
client := s3.NewFromConfig(cfg, func (o *svc.Options) { o.BaseEndpoint = aws.String("https://localhost:8080/") })
Com EndpointResolverV2
O trecho de código a seguir mostra como injetar um comportamento personalizado na resolução do endpoint do S3 usando 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{ // ... } }) }
Com ambos
O exemplo de programa a seguir demonstra a interação entre BaseEndpoint e EndpointResolverV2. Este é um caso de uso avançado:
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) }
Quando executado, o programa acima gera o seguinte:
The endpoint provided in config is https://endpoint.dev/
V1: EndpointResolver
Atenção
A resolução de endpoint da v1 é mantida para fins de compatibilidade com versões anteriores e é isolada do comportamento moderno na resolução de endpoint da v2. Ela só será usada se o campo EndpointResolver for definido pelo chamador.
O uso da v1 provavelmente impedirá que você acesse os recursos de serviço relacionados ao endpoint introduzidos com ou após o lançamento da resolução v2. Consulte instruções sobre como fazer upgrade em “Migração”.
Um EndpointResolverEndpointResolverWithOptions.
Um EndpointResolver pode ser facilmente configurado passando o resolvedor encapsulado com WithEndpointResolverWithOptionsaws.Config resultante com seu resolvedor de endpoint personalizado.
O resolvedor de endpoint recebe o serviço e a região como uma string, permitindo que o resolvedor conduza dinamicamente seu comportamento. Cada pacote de cliente de serviço tem uma constante ServiceID exportada que pode ser usada para determinar qual cliente de serviço está invocando o resolvedor de endpoint.
Um resolvedor de endpoint pode usar o valor de erro sentinela EndpointNotFoundError
Se a implementação do resolvedor de endpoint retornar um erro diferente de EndpointNotFoundError, a resolução do endpoint será interrompida e a operação de serviço retornará um erro para a aplicação.
Exemplos
Com fallback
O trecho de código a seguir mostra como um único endpoint de serviço pode ser substituído para o DynamoDB pelo comportamento com fallback para outros endpoints:
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))
Sem fallback
O trecho de código a seguir mostra como um único endpoint de serviço pode ser substituído para o DynamoDB pelo comportamento sem fallback para outros endpoints:
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))
Endpoints imutáveis
Atenção
Definir um endpoint como imutável pode impedir que alguns recursos do cliente de serviço funcionem corretamente e pode resultar em um comportamento indefinido. Deve-se ter cautela ao definir um endpoint como imutável.
Alguns clientes de serviço, como o Amazon S3, podem modificar o endpoint retornado pelo resolvedor para determinadas operações de serviço. Por exemplo, o Amazon S3 gerencia automaticamente o Endereçamento de bucket virtual alterando o endpoint resolvido. Você pode evitar que o SDK altere seus endpoints personalizados definindo HostnameImmutabletrue. Por exemplo:
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))
Migração
Ao migrar da v1 para v2 da resolução de endpoint, os seguintes princípios gerais se aplicam:
-
Retornar um endpoint
com HostnameImmutable definido como falseé praticamente equivalente a configurarBaseEndpointcomo o URL originalmente retornado da v1 e deixarEndpointResolverV2como padrão. -
Retornar um endpoint com HostnameImmutable definido como
trueé praticamente equivalente à implementação de umEndpointResolverV2que retorna o URL originalmente retornado da v1.-
A principal exceção é para operações com prefixos de endpoint modelados. Há uma nota sobre isso mais abaixo.
-
Exemplos desses casos são fornecidos abaixo.
Atenção
Os endpoints imutáveis da V1 e a resolução V2 não são equivalentes em comportamento. Por exemplo, substituições de assinatura para recursos personalizados, como o S3 Object Lambda, ainda seriam definidas para endpoints imutáveis retornados por meio do código da v1, mas o mesmo não será feito para a v2.
Nota sobre prefixos de host
Algumas operações são modeladas com prefixos de host a serem anexados ao endpoint resolvido. Esse comportamento deve funcionar em conjunto com a saída de ResolveEndpointV2 e, portanto, o prefixo do host ainda será aplicado a esse resultado.
Você pode desativar manualmente o prefixo do host do endpoint aplicando um middleware. Consulte a seção de exemplos.
Exemplos
Endpoint mutável
O exemplo de código a seguir demonstra como migrar um resolvedor de endpoint básico da v1 que retorna um endpoint modificável:
// 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/") })
Endpoint imutável
// 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{} })
Desativar o prefixo do host
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) } }