You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:12:37