AWS预签名URL设6天有效期却1小时失效,求调试指引
以下是你的AWS客户端初始化及预签名URL生成代码:
客户端初始化代码
type AWSClient struct { uploader *manager.Uploader downloader *manager.Downloader psClient *s3.PresignClient s3Client *s3.Client sesClient *sesv2.Client } func NewAWSClient() AWSClient { log.Println("Configuring AWS ...") cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatal(err) panic("Error configuring AWS.") } s3Client := s3.NewFromConfig(cfg) sesClient := sesv2.NewFromConfig(cfg) return AWSClient{ s3Client: s3Client, uploader: manager.NewUploader(s3Client), downloader: manager.NewDownloader(s3Client), psClient: s3.NewPresignClient(s3Client), sesClient: sesClient, } }
预签名URL生成代码
func (c AWSClient) GetPresignedURL(ctx context.Context, awsBucket string, key string, ttl time.Duration) (string, entity.Error) { logger := rctx.LoggerWithFn(ctx) input := &s3.GetObjectInput{ Key: &key, Bucket: &awsBucket, } resp, err := c.psClient.PresignGetObject(context.TODO(), input, s3.WithPresignExpires(ttl)) // 6 days expiry. if err != nil { logger.Log(p.Error, "error retrieving pre-signed object: "+err.Error()) return "", entity.InternalError(err) } return resp.URL, nil }
针对设置6天有效期但实际1小时过期的问题,可按以下思路调试:
验证TTL参数传递正确性
在GetPresignedURL函数开头添加日志,打印传入的ttl具体值,确认是否确实为6天(即6*24*time.Hour)。同时检查上层调用代码,确认参数未被错误覆盖为1小时。示例日志代码:logger.Log(p.Info, fmt.Sprintf("Requested TTL: %v", ttl))检查凭证有效期限制
若使用临时凭证(如IAM角色、STS凭证),预签名URL的有效期不能超过凭证本身的过期时间。很多临时凭证默认有效期为1小时,此时即使设置更长TTL,URL实际有效期也会被限制为凭证剩余时长。可在客户端初始化时打印凭证过期时间:creds, err := cfg.Credentials.Retrieve(context.TODO()) if err == nil { log.Printf("Credential expiry: %v", creds.Expires) }解析预签名URL的过期参数
查看生成的URL中X-Amz-Expires参数值(单位为秒),6天对应518400秒,若该值为3600(1小时),说明SDK未正确应用设置的TTL。可打印URL的查询参数确认:logger.Log(p.Info, fmt.Sprintf("Presigned URL query params: %s", resp.URL.RawQuery))排查PresignClient配置
确认创建PresignClient时未设置默认过期时间覆盖后续参数。当前代码中NewPresignClient无额外配置,但若后续修改时传入了自定义PresignOptions并设置了Expires,会导致所有预签名URL使用该默认值。测试最小化场景
编写独立测试程序,直接初始化客户端并生成预签名URL,排除业务代码中的干扰因素。如果测试程序能生成正确有效期的URL,说明问题出在业务逻辑的参数传递或上下文处理环节。示例测试代码:package main import ( "context" "fmt" "log" "time" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) func main() { cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatal(err) } s3Client := s3.NewFromConfig(cfg) psClient := s3.NewPresignClient(s3Client) input := &s3.GetObjectInput{ Key: aws.String("test-key"), Bucket: aws.String("test-bucket"), } ttl := 6 * 24 * time.Hour resp, err := psClient.PresignGetObject(context.TODO(), input, s3.WithPresignExpires(ttl)) if err != nil { log.Fatal(err) } fmt.Printf("Presigned URL: %s\n", resp.URL) fmt.Printf("X-Amz-Expires: %s\n", resp.URL.Query().Get("X-Amz-Expires")) }检查存储桶策略限制
虽然少见,但部分Bucket Policy可能通过Condition项限制x-amz-expires的值,需确认存储桶策略未添加此类限制。
内容的提问来源于stack exchange,提问作者RajdeepPal

