Configuración de puntos de conexión del cliente - AWS SDK para Go v2

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Configuración de puntos de conexión del cliente

aviso

La resolución de puntos de conexión es un tema avanzado del SDK. Al cambiar esta configuración, corre el riesgo de invalidar el código. La configuración predeterminada debe poder aplicarse a la mayoría de los usuarios en entornos de producción.

AWS SDK para Go ofrece la posibilidad de configurar un punto de conexión personalizado de modo que pueda usarse para un servicio. En muchos casos, la configuración predeterminada será suficiente. La configuración de puntos de conexión personalizados permite un comportamiento adicional, como trabajar con versiones previas al lanzamiento de un servicio.

Personalización

Existen dos “versiones” de la configuración de resolución de puntos de conexión en el SDK:

  • v2, publicada en el tercer trimestre de 2023, configurada mediante:

    • EndpointResolverV2

    • BaseEndpoint

  • v1, publicada junto con el SDK, configurada mediante:

    • EndpointResolver

Recomendamos a los usuarios de la resolución de puntos de conexión v1 que migren a la versión 2 para obtener acceso a características del servicio más recientes relacionadas con estos.

V2: EndpointResolverV2 + BaseEndpoint

En la versión 2 de la resolución, EndpointResolverV2 es el mecanismo definitivo a través del cual se produce la resolución de puntos de conexión. El método ResolveEndpoint del solucionador se invoca como parte del flujo de trabajo para cada solicitud que realice en el SDK. El nombre de host del Endpoint devuelto por el solucionador se usa tal cual al realizar la solicitud (sin embargo, los serializadores de operaciones pueden seguir asociando elementos a la ruta HTTP).

En la resolución v2 se incluye una configuración adicional de nivel de cliente, BaseEndpoint, que se utiliza a fin de especificar un nombre de host “base” para la instancia de su servicio. El valor establecido aquí no es definitivo: se pasa en última instancia como parámetro al EndpointResolverV2 del cliente cuando se produce la resolución final (siga leyendo para obtener más información sobre los parámetros EndpointResolverV2). La implementación del solucionador tiene entonces la oportunidad de inspeccionar y, posiblemente, modificar ese valor para determinar el punto de conexión final.

Por ejemplo, si realiza una solicitud GetObject de S3 en un bucket determinado con un cliente en el que ha especificado un BaseEndpoint, el solucionador predeterminado inyectará el bucket en el nombre del host si es compatible con el host virtual (suponiendo que no haya desactivado el alojamiento virtual en la configuración del cliente).

En la práctica, lo más probable es que BaseEndpoint se utilice para dirigir al cliente a una instancia de desarrollo o de vista previa de un servicio.

EndpointResolverV2Parámetros

Cada servicio toma un conjunto específico de entradas que se pasan a su función de resolución, definida en cada paquete de servicios como EndpointParameters.

Cada servicio incluye los siguientes parámetros base, que se utilizan para facilitar la resolución de puntos de conexión general en AWS:

nombre tipo description
Region string Indica la región de AWS del cliente.
Endpoint string Indica el valor establecido para BaseEndpoint en la configuración del cliente.
UseFips bool Indica si los puntos de conexión de FIPS están habilitados en la configuración del cliente.
UseDualStack bool Indica si los puntos de conexión de doble pila están habilitados en la configuración del cliente.

Los servicios pueden especificar parámetros adicionales necesarios para la resolución. Por ejemplo, los EndpointParameters de S3 incluyen el nombre del bucket, así como varios ajustes de características específicos de S3 (por ejemplo, si el direccionamiento de host virtual está habilitado).

Si implementa su propio EndpointResolverV2, no debería tener que crear una instancia propia de EndpointParameters en ningún caso. El SDK obtendrá los valores por solicitud y los pasará a su implementación.

Nota acerca de Amazon S3

Amazon S3 es un servicio complejo con muchas de sus características modeladas a través de complejas personalizaciones de puntos de conexión, como el alojamiento virtual de buckets o el punto de acceso multirregional de S3, entre otras.

Por ello, recomendamos que no reemplace la implementación de EndpointResolverV2 en su cliente de S3. Si necesita ampliar su comportamiento de resolución (por ejemplo, mediante el envío de solicitudes a una pila de desarrollo local con consideraciones adicionales sobre los puntos de conexión), recomendamos encapsular la implementación predeterminada de forma que se delegue de nuevo en esta como alternativa (como se muestra en los ejemplos que aparecen a continuación).

Ejemplos

Con BaseEndpoint

El fragmento de código siguiente muestra cómo apuntar su cliente de S3 a la instancia local de un servicio, que en este ejemplo se aloja en el dispositivo de bucle invertido en el puerto 8080.

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

Con EndpointResolverV2

El fragmento de código siguiente muestra cómo inyectar un comportamiento personalizado en la resolución de puntos de conexión de S3 mediante 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{ // ... } }) }

Con ambos

El programa de ejemplo siguiente demuestra la interacción entre BaseEndpoint y EndpointResolverV2. Este es un caso de uso avanzado:

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) }

Cuando se ejecuta, el programa anterior genera lo siguiente:

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

V1: EndpointResolver

aviso

La resolución de puntos de conexión v1 se conserva por motivos de compatibilidad con versiones anteriores y está aislada del comportamiento moderno de la resolución de puntos de conexión v2. Solo se usará si el intermediario establece el campo EndpointResolver.

Lo más probable es que el uso de la versión 1 le impida acceder a las características del servicio relacionadas con los puntos de conexión que se introdujeron con el lanzamiento de la resolución v2 o después de este. Consulte “Migración” para obtener instrucciones sobre cómo actualizar.

Se puede configurar un elemento EndpointResolver para proporcionar una lógica de resolución de puntos de conexión personalizada a los clientes de servicio. Puede utilizar un solucionador de puntos de conexión personalizado para reemplazar la lógica de resolución de puntos de conexión de un servicio para todos los puntos de conexión o solo para un punto de conexión regional específico. Un solucionador de puntos de conexión personalizado puede desencadenar la lógica de resolución de puntos de conexión del servicio como alternativa, en caso de que el solucionador personalizado no desee resolver un punto de conexión solicitado. Se puede usar EndpointResolverWithOptionsFunc para encapsular funciones de forma fácil a fin de que cumplan con la interfaz EndpointResolverWithOptions.

Configurar un elemento EndpointResolver es fácil. Para ello, pase el solucionador encapsulado con WithEndpointResolverWithOptions a LoadDefaultConfig, lo que permite reemplazar puntos de conexión al cargar credenciales, además de configurar el elemento aws.Config resultante con su solucionador de puntos de conexión personalizado.

El solucionador de puntos de conexión recibe el servicio y la región en forma de cadena, lo que le permite controlar su comportamiento de forma dinámica. Cada paquete de clientes de servicio tiene una constante ServiceID exportada que se puede utilizar para determinar qué cliente de servicio invoca el solucionador de puntos de conexión.

Un solucionador de puntos de conexión puede utilizar el valor de error de sentinel EndpointNotFoundError para desencadenar la resolución alternativa hacia la lógica de resolución predeterminada de los clientes de servicio. Esto permite reemplazar de forma selectiva uno o varios puntos de conexión sin problemas y sin tener que gestionar una lógica alternativa.

Si la implementación del solucionador de puntos de conexión devuelve un error distinto de EndpointNotFoundError, la resolución de puntos de conexión se detiene y la operación del servicio devuelve un error a la aplicación.

Ejemplos

Con alternativa

El fragmento de código siguiente muestra cómo se puede reemplazar un único punto de conexión de servicio para DynamoDB con un comportamiento alternativo para otros puntos de conexión:

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))

Sin alternativa

El fragmento de código siguiente muestra cómo se puede reemplazar un único punto de conexión de servicio para DynamoDB sin un comportamiento alternativo para otros puntos de conexión:

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))

Puntos de conexión inmutables

aviso

Establecer un punto de conexión como inmutable puede impedir que algunas de las características del cliente de servicio funcionen correctamente, lo que podría provocar un comportamiento indefinido. Se debe tener cuidado a la hora de definir un punto de conexión como inmutable.

Algunos clientes de servicio, como Amazon S3, pueden modificar el punto de conexión devuelto por el solucionador para determinadas operaciones de servicio. Por ejemplo, Amazon S3 gestionará de forma automática el direccionamiento virtual de buckets al mutar el punto de conexión resuelto. Puede evitar que el SDK mute sus puntos de conexión personalizados al establecer HostnameImmutable en true. Por ejemplo:

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))

Migración

Al migrar de la versión 1 a la versión 2 de la resolución de puntos de conexión, se aplican los siguientes principios generales:

  • Devolver un punto de conexión con el valor HostnameImmutable establecido en false es más o menos equivalente a establecer BaseEndpoint en la URL devuelta originalmente desde la versión 1 y dejar EndpointResolverV2 como valor predeterminado.

  • Devolver un punto de conexión con el valor HostnameImmutable establecido en true es más o menos equivalente a implementar un EndpointResolverV2 que devuelve la URL originalmente devuelta desde la versión 1.

    • La excepción principal se da en el caso de las operaciones con prefijos de punto de conexión modelados. Más adelante se incluye una nota al respecto.

A continuación, se proporcionan ejemplos de estos casos.

aviso

Los puntos de conexión inmutables de la versión 1 y la resolución de la versión 2 no tienen un comportamiento equivalente. Por ejemplo, los reemplazos de firma para características personalizadas como S3 Object Lambda seguirían estableciéndose para los puntos de conexión inmutables devueltos mediante código de la versión 1, pero no se haría lo mismo en el caso de la versión 2.

Nota sobre los prefijos de host

Algunas operaciones se modelan con prefijos de host que se anteponen al punto de conexión resuelto. Este comportamiento debe funcionar en conjunto con la salida de ResolveEndpointV2 y, por lo tanto, el prefijo de host se seguirá aplicando a ese resultado.

Puede deshabilitar el prefijo de host del punto de conexión de forma manual mediante la aplicación de un middleware (consulte la sección de ejemplos).

Ejemplos

Punto de conexión mutable

En el ejemplo de código siguiente se muestra cómo migrar un solucionador de puntos de conexión básico de la versión 1 que devuelve un punto de conexión modificable:

// 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/") })

Punto de conexión inmutable

// 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{} })

Deshabilitación del prefijo de 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) } }