Padrões de SDK S3/GCS com aws-sdk-go-v2
O armazenamento de objetos é a espinha dorsal do Go serverless: uploads de usuários, arquivos de exportação, payloads de eventos e ativos estáticos.
Busque em todas as páginas da documentação
O armazenamento de objetos é a espinha dorsal do Go serverless: uploads de usuários, arquivos de exportação, payloads de eventos e ativos estáticos.
aws-sdk-go-v2 e cloud.google.com/go/storage recompensam os mesmos hábitos: clientes compartilhados, deadlines de contexto, chaves idempotentes e compreensão explícita de retentativas.
Construa clientes S3 uma vez com config.LoadDefaultConfig e reutilize-os entre invocações no Lambda ou goroutines no Cloud Run.
Passe r.Context() de manipuladores HTTP para PutObject e GetObject para que os timeouts da plataforma cancelem uploads em andamento.
Use chaves de objeto determinísticas ou baseadas em hash de conteúdo para que as retentativas não criem arquivos duplicados visíveis para o usuário.
Cartão de receita de referência rápida - pronto para copiar e colar.
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"),
})Quando usar isso:
Put/Get por trás de uma pequena interface.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 impede a sobrescrita quando ocorrem corridas de retentativa (cabeçalhos condicionais 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)
}O que isso demonstra:
NewS3Uploader.ctx em PutObject e GetObject.Retentativas se aplicam a throttling e respostas transitórias 5xx com backoff - não são um substituto para lógica de aplicação idempotente.
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 { /* ... */ }Sempre Close() os escritores GCS para confirmar objetos.
| Camada | Origem | Valor Típico |
|---|---|---|
| API Gateway / Cloud Run | Proxy da Plataforma | 30-60s |
http.Server | ReadTimeout / manipulador | 15-30s |
| Manipulador | context.WithTimeout | Ligeiramente abaixo do servidor |
| Chamada SDK | Mesmo ctx passado para PutObject | Herda o pai |
Se o ctx do manipulador expirar no meio do upload, o SDK aborta e o S3 pode ou não ter confirmado - projete chaves para que uma retentativa seja segura.
manager.Uploader de feature/s3/manager para arquivos maiores que alguns MB.PartSize e Concurrency conservadoramente em ambientes Lambda com memória limitada.manager.Downloader transmite para io.Writer sem carregar objetos inteiros na RAM.| Cenário | Seguro para retentativa SDK? | Padrão da Aplicação |
|---|---|---|
| PUT mesma chave mesmos bytes | Sim | Chave de hash de conteúdo |
| PUT nova versão | Cuidado | VersionId ou UUID na chave |
| DELETE | Frequentemente sim | Flags de "tombstone" |
| LIST + PUT condicional | Não | Use um armazenamento de metadados transacional |
sync.Once no nível do pacote ou injetado na inicialização.ctx - Uploads continuam após a desconexão do cliente. Correção: Passe o contexto do manipulador para as chamadas SDK.io.Copy e corpo de GetObject.Writer.Close no GCS - Objetos nunca são finalizados. Correção: Sempre verifique o erro de Close().s3:* curinga em * - Permissões excessivamente amplas. Correção: Prefixo ARNs por bucket e apenas PutObject/GetObject.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| URLs Pré-assinadas | Upload direto pelo navegador | O servidor precisa transformar bytes primeiro |
| Aceleração de Transferência S3 | Latência de upload global | Pipelines internos sensíveis a custo |
| Rclone / Sidecar CLI | Scripts de operações | Controle Go em processo necessário |
| URLs assinadas GCS | Uploads pelo navegador GCP | Pilhas apenas AWS |
Comece com código Go novo em aws-sdk-go-v2 - importações modulares, middleware Smithy, desenvolvimento ativo.
v1 está em modo de manutenção.
O SDK retenta com backoff; adicione retentativa em nível de aplicação com jitter apenas para operações idempotentes e considere aumentar os limites de taxa de requisição com a AWS.
Sim - defina Put(ctx, key, r io.Reader) e Get(ctx, key) em internal/storage com adaptadores específicos da nuvem para testes.
Anexe uma role de execução com IAM com escopo de bucket; construa o cliente uma vez por ambiente de execução com LoadDefaultConfig.
Habilite SSE-S3 ou SSE-KMS por padrão para buckets de conformidade; passe ServerSideEncryption em PutObjectInput ou política de criptografia padrão do bucket.
Versões da Stack: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, go fix modernizers - verifique o patch na compilação), chi (última versão - verifique na compilação), gin (última versão - verifique na compilação), echo (última versão - verifique na compilação), google.golang.org/grpc (última versão - verifique na compilação), sigs.k8s.io/controller-runtime (última versão - verifique na compilação), kubebuilder (última versão - verifique na compilação), tinygo (última versão - verifique os alvos de placa na compilação), wazero (última versão - verifique na compilação) e golangci-lint (última versão - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026