Patrones de SDK para S3/GCS con aws-sdk-go-v2
El almacenamiento de objetos es la columna vertebral de Go sin servidor: cargas de usuarios, archivos de exportación, cargas útiles de eventos y activos estáticos.
Busca en todas las páginas de la documentación
El almacenamiento de objetos es la columna vertebral de Go sin servidor: cargas de usuarios, archivos de exportación, cargas útiles de eventos y activos estáticos.
aws-sdk-go-v2 y cloud.google.com/go/storage recompensan los mismos hábitos: clientes compartidos, plazos de contexto, claves idempotentes y comprensión explícita de reintentos.
Crea clientes S3 una vez con config.LoadDefaultConfig y reutilízalos en invocaciones en Lambda o goroutines en Cloud Run.
Pasa r.Context() desde los manejadores HTTP a PutObject y GetObject para que los tiempos de espera de la plataforma cancelen las cargas en curso.
Utiliza claves de objeto dirigidas por contenido o deterministas para que los reintentos no creen archivos duplicados visibles para el usuario.
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
cfg, err := config.LoadDefaultConfig(ctx)
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.RetryMaxAttempts = 5
})
_, err = client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: body,
ContentType: aws.String("application/json"),
})Cuándo usar esto:
Put/Get detrás de una pequeña interfaz.package storage
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"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"
)
type S3Uploader struct {
client *s3.Client
bucket string
}
func NewS3Uploader(ctx context.Context, bucket, region string) (*S3Uploader, error) {
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
if err != nil {
return nil, fmt.Errorf("load aws config: %w", err)
}
return &S3Uploader{
client: s3.NewFromConfig(cfg),
bucket: bucket,
}, nil
}
func (u *S3Uploader) PutJSONIdempotent(ctx context.Context, prefix string, payload []byte) (string, error) {
sum := sha256.Sum256(payload)
key := fmt.Sprintf("%s/%s.json", prefix, hex.EncodeToString(sum[:]))
_, err := u.client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(u.bucket),
Key: aws.String(key),
Body: bytes.NewReader(payload),
ContentType: aws.String("application/json"),
// IfNoneMatch evita la sobrescritura cuando ocurren carreras de reintentos (cabeceras condicionales de S3)
})
if err != nil {
return "", fmt.Errorf("put object %s: %w", key, err)
}
return key, nil
}
func (u *S3Uploader) Get(ctx context.Context, key string) ([]byte, error) {
out, err := u.client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(u.bucket),
Key: aws.String(key),
})
if err != nil {
return nil, fmt.Errorf("get object: %w", err)
}
defer out.Body.Close()
return io.ReadAll(out.Body)
}Lo que esto demuestra:
NewS3Uploader.ctx tanto en PutObject como en GetObject.Los reintentos se aplican a la limitación y a las respuestas transitorias 5xx con retroceso, no son un sustituto de la lógica idempotente de la aplicación.
gcsClient, err := storage.NewClient(ctx)
w := gcsClient.Bucket(bucket).Object(key).NewWriter(ctx)
if _, err := io.Copy(w, bytes.NewReader(payload)); err != nil { /* ... */ }
if err := w.Close(); err != nil { /* ... */ }Siempre Close() los escritores GCS para confirmar los objetos.
| Capa | Fuente | Valor Típico |
|---|---|---|
| API Gateway / Cloud Run | Proxy de plataforma | 30-60s |
http.Server | ReadTimeout / manejador | 15-30s |
| Manejador | context.WithTimeout | Ligeramente por debajo del servidor |
| Llamada SDK | El mismo ctx pasado a PutObject | Hereda del padre |
Si el contexto del manejador expira a mitad de la carga, el SDK aborta y S3 puede o no haber confirmado; diseña claves para que un reintento sea seguro.
manager.Uploader de feature/s3/manager para archivos de más de unos pocos MB.PartSize y Concurrency de forma conservadora en entornos Lambda con memoria limitada.manager.Downloader transmite a io.Writer sin cargar objetos completos en RAM.| Escenario | ¿Reintento SDK seguro? | Patrón de aplicación |
|---|---|---|
| PUT misma clave mismos bytes | Sí | Clave de hash de contenido |
| PUT nueva versión | Cuidado | VersionId o UUID en la clave |
| DELETE | A menudo sí | Indicadores de "tombstone" |
| LIST + PUT condicional | No | Utilizar un almacén de metadatos transaccional |
sync.Once a nivel de paquete o inyectado al inicio.ctx - Las cargas continúan después de la desconexión del cliente. Solución: Pasar el contexto del manejador a las llamadas SDK.io.Copy y el cuerpo de GetObject.Writer.Close de GCS - Los objetos nunca se finalizan. Solución: Siempre comprueba el error de Close().s3:* en * - Roles demasiado amplios. Solución: Prefijos ARN por bucket y solo PutObject/GetObject.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| URLs pre-firmadas | Carga directa del navegador | El servidor debe transformar bytes primero |
| S3 Transfer Acceleration | Latencia de carga global | Tuberías internas sensibles al costo |
| Rclone / Sidecar CLI | Scripts de operaciones | Se requiere control en proceso de Go |
| URLs firmadas de GCS | Cargas del navegador GCP | Pila solo de AWS |
Comienza el nuevo código Go en aws-sdk-go-v2: importaciones modulares, middleware Smithy, desarrollo activo.
v1 está en modo de mantenimiento.
El SDK reintenta con retroceso; añade un reintento a nivel de aplicación con jitter solo para operaciones idempotentes y considera aumentar los límites de tasa de solicitud con AWS.
Sí: define Put(ctx, key, r io.Reader) y Get(ctx, key) en internal/storage con adaptadores específicos de la nube para pruebas.
Adjunta un rol de ejecución con IAM con ámbito de bucket; construye el cliente una vez por entorno de ejecución con LoadDefaultConfig.
Habilita SSE-S3 o SSE-KMS por defecto para los buckets de cumplimiento; pasa ServerSideEncryption en PutObjectInput o la política de cifrado predeterminada del bucket.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado Green Tea GC, go fix modernizers - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación) y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026