如何在Go的aws-sdk-go-v2中检测S3 OperationError超时错误?
问题
我用aws-sdk-go-v2实现了一段通过MultipartUpload将文件上传至S3存储桶的代码,当服务器不可用时,代码会抛出如下错误:
operation error S3: CreateMultipartUpload, https response error StatusCode: 0, RequestID: , HostID: , request send failed, Post "http://[...]?uploads=&x-id=CreateMultipartUpload": dial tcp xx.xx.x.xxx:xx: i/o timeout
该错误由s3.Client.CreateMultipartUpload返回。我希望识别这类超时错误(无需修复,仅做判断),除了解析错误字符串中的i/o timeout外,有没有更优雅的方式?
以下是我尝试过但无效的代码:
var oe *smithy.OperationError if errors.As(err, &oe) { fmt.Printf("Attempt 1 %t\n", errors.Is(err, os.ErrDeadlineExceeded)) fmt.Printf("Attempt 2 %t\n", errors.Is(oe.Unwrap(), os.ErrDeadlineExceeded)) if netErr, ok := err.(net.Error); ok && netErr.Temporary() { fmt.Printf("Attempt 3\n") } if netErr, ok := oe.Unwrap().(net.Error); ok && netErr.Temporary() { fmt.Printf("Attempt 4\n") } if netErr, ok := err.(net.Error); ok && netErr.Timeout() { fmt.Printf("Attempt 3\n") } if netErr, ok := oe.Unwrap().(net.Error); ok && netErr.Timeout() { fmt.Printf("Attempt 4\n") } fmt.Printf("Attempt 5 %t\n", os.IsTimeout(err)) fmt.Printf("Attempt 6 %t\n", os.IsTimeout(oe.Unwrap())) }
解决方案
可以通过递归遍历错误链或结合AWS SDK的错误类型实现优雅判断,以下是两种可行方案:
方案一:用errors.As遍历错误链找超时错误
errors.As会自动遍历整个错误链,无需手动逐层unwrap,直接查找底层的net.Error并判断是否为超时类型:
import ( "errors" "net" ) func isTimeoutError(err error) bool { var netErr net.Error return errors.As(err, &netErr) && netErr.Timeout() }
使用示例:
if isTimeoutError(err) { // 确认是超时错误,执行对应逻辑 }
方案二:针对S3操作的精准判断
结合smithy.OperationError和AWS SDK的awshttp.ResponseError,精准定位S3上传的超时错误:
import ( "errors" "net" "github.com/aws/aws-sdk-go-v2/aws/awshttp" "github.com/aws/smithy-go" ) func isS3MultipartUploadTimeout(err error) bool { var opErr *smithy.OperationError if !errors.As(err, &opErr) { return false } // 先检查是否是ResponseError包装的错误 var respErr *awshttp.ResponseError if errors.As(opErr.Unwrap(), &respErr) { var netErr net.Error return errors.As(respErr.Err, &netErr) && netErr.Timeout() } // 处理其他直接包装net.Error的情况 var netErr net.Error return errors.As(opErr.Unwrap(), &netErr) && netErr.Timeout() }
之前尝试无效的原因
你之前仅unwrap了一层smithy.OperationError,但实际错误链可能存在多层包装(比如smithy.OperationError → awshttp.ResponseError → net.Error),直接断言oe.Unwrap()为net.Error会失败。而errors.As会自动遍历整个错误链,能正确定位到底层的超时错误。
内容的提问来源于stack exchange,提问作者Nu Nunu
相关产品推荐
相关产品推荐

