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

Golang上传视频至Amazon S3遇501错误及空指针恐慌求助

问题描述

我用Golang做后端开发了一款支持图片和视频上传的应用,图片上传功能一直正常,视频上传此前也能正常运行,但现在出现了问题——这个错误和某个GitHub issue里的错误一致。我已经确认视频文件确实传输过来了(返回的文件有正确大小),但在执行S3的PutObject操作时持续报错。

上传视频的代码

func UploadStreamVideo(w http.ResponseWriter, r *http.Request) { 
    r.ParseForm() 
    var buf bytes.Buffer 
    sess, _ := session.NewSession(&aws.Config{ 
        Region: aws.String("us-west-2"), 
        Credentials: credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, ""), 
    }) 
    svc := s3.New(sess) 

    file, handler, err := r.FormFile("file") 
    if err != nil { 
        log_errors("HomePage-UploadStreamImage: error receiving file", err.Error(), w) 
        fmt.Println("Error Uploading Image") 
        return 
    } 
    defer file.Close() 

    println(handler.Filename) // 能正常打印文件名
    println(handler.Size)     // 也能看到文件大小

    read_file, err := ioutil.ReadAll(file) 
    if err != nil { 
        log_errors("HomePage-UploadStreamImage") 
        return 
    } 
    file.Read(read_file) 
    fileBytes := bytes.NewReader(read_file) 
    fileSize, err := buf.ReadFrom(file) 
    if err != nil { 
        log_errors("HomePage-UploadStreamImage") 
    } 

    fileType := http.DetectContentType(read_file) 
    path := handler.Filename 

    params := &s3.PutObjectInput{ 
        Bucket: aws.String("yisl"), 
        Key: aws.String(path), 
        Body: fileBytes, 
        ContentLength: aws.Int64(fileSize), 
        ContentType: aws.String(fileType), 
    } 

    // 下面这行代码报错
    _, err = svc.PutObject(params) 
    if err != nil { 
        println(err.Error()) 
        log_errors("HomePage-UploadStreamImage") 
        return 
    } 

    io.WriteString(w, "Done") 
}

错误信息

NotImplemented: A header you provided implies functionality that is not implemented 
status code: 501, request id: 310D0CE7643E1B4B, host id: GUB8UDi9KJTIPybXh3I1m5Vu8Ixyt4LQv5PbVnyOH2ngAdtOv0DsyALHp1mMI3SmRpK+xHV3uds= 
> 2018/05/12 03:30:21 http: panic serving [::1]:64945: runtime error: 
> invalid memory address or nil pointer dereference 
goroutine 10 
> [running]: net/http.(*conn).serve.func1(0xc420229400) 
> /usr/local/go/src/net/http/server.go:1726 +0xd0 
panic(0x1451b20, 0x1752c30) /usr/local/go/src/runtime/panic.go:502 +0x229 
> database/sql.(*Rows).close(0x0, 0x0, 0x0, 0x0, 0x0) 
> /usr/local/go/src/database/sql/sql.go:2907 +0x6b 
> database/sql.(*Rows).Close(0x0, 0x14f5698, 0x4d) 
> /usr/local/go/src/database/sql/sql.go:2903 +0x33 
> _/Users/ignaciohernandez/Documents/go/Yisly-Backend/Controllers.log_errors(0x14ef38b, 0x2e, 0xc42010aa80, 0xda, 0x15737c0, 0xc420244380) 
> /Users/ignaciohernandez/Documents/go/Yisly-Backend/Controllers/function_store.go:27 
> +0x2d8 
> _/Users/ignaciohernandez/Documents/go/Yisly-Backend/Controllers.UploadStreamVideo(0x15737c0, 0xc420244380, 0xc420211700) 
> /Users/ignaciohernandez/Documents/go/Yisly-Backend/Controllers/HomePage.go:377 
> +0x7ad 
net/http.HandlerFunc.ServeHTTP(0x14fd130, 0x15737c0, 0xc420244380, 0xc420211700) /usr/local/go/src/net/http/server.go:1947 
> +0x44 
github.com/gorilla/mux.(*Router).ServeHTTP(0xc420142380, 0x15737c0, 0xc420244380, 0xc420211700) 
> /Users/ignaciohernandez/Documents/go/src/github.com/gorilla/mux/mux.go:162 
> +0xed 
net/http.(*ServeMux).ServeHTTP(0x1760f20, 0x15737c0, 0xc420244380, 0xc420211500) /usr/local/go/src/net/http/server.go:2337 
> +0x130 
net/http.serverHandler.ServeHTTP(0xc4201c89c0, 0x15737c0, 0xc420244380, 0xc420211500) /usr/local/go/src/net/http/server.go:2694 
> +0xbc 
net/http.(*conn).serve(0xc420229400, 0x1573b40, 0xc42002c9c0) /usr/local/go/src/net/http/server.go:1830 +0x651 
created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2795 
> +0x27b

解决建议

我帮你梳理下代码里的问题,以及对应的解决办法:

1. 修复文件读取的逻辑错误

你的文件读取流程完全混乱了,这是导致S3 PutObject报错的核心原因:

  • 先用ioutil.ReadAll(file)把整个文件读进了read_file,此时文件指针已经移到末尾;
  • 后续调用file.Read(read_file)完全无效,因为已经没有内容可读;
  • 再调用buf.ReadFrom(file)自然读取到的fileSize是0,把这个0传给ContentLength后,和Body里实际的文件内容产生矛盾,触发了S3的501错误。

修复后的文件读取逻辑可以简化成这样:

file, handler, err := r.FormFile("file")
if err != nil {
    log_errors("HomePage-UploadStreamVideo: error receiving file", err.Error(), w)
    fmt.Println("Error Uploading Video")
    return
}
defer file.Close()

// 直接读取整个文件到字节数组
read_file, err := ioutil.ReadAll(file)
if err != nil {
    log_errors("HomePage-UploadStreamVideo: failed to read file", err.Error(), w)
    return
}

fileBytes := bytes.NewReader(read_file)
// 直接用handler.Size作为文件大小,不需要重复读取
fileSize := handler.Size
fileType := http.DetectContentType(read_file)
path := handler.Filename

2. 修正S3 PutObject参数

把ContentLength设置为正确的文件大小(可以用handler.Size或者int64(len(read_file))),避免传递无效的0值:

params := &s3.PutObjectInput{
    Bucket:        aws.String("yisl"),
    Key:           aws.String(path),
    Body:          fileBytes,
    ContentLength: aws.Int64(fileSize), // 这里用正确的文件大小
    ContentType:   aws.String(fileType),
}

3. 不要忽略Session创建的错误

之前session.NewSession的错误被你直接忽略了,这可能导致后续S3客户端初始化异常,必须加上错误检查:

sess, err := session.NewSession(&aws.Config{
    Region:      aws.String("us-west-2"),
    Credentials: credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, ""),
})
if err != nil {
    log_errors("HomePage-UploadStreamVideo: failed to create AWS session", err.Error(), w)
    return
}
svc := s3.New(sess)

4. 修复log_errors函数的nil指针Panic

从错误栈可以看到,Panic是因为log_errors里调用了(*Rows).Close(),但传入的Rows对象是nil。你需要修改这个函数,先判断参数是否为nil再执行操作:

func log_errors(msg string, errMsg string, w http.ResponseWriter, rows ...*sql.Rows) {
    // 先处理日志输出
    fmt.Printf("Error: %s - %s\n", msg, errMsg)
    // 仅当Rows参数存在且不为nil时,才执行Close
    if len(rows) > 0 && rows[0] != nil {
        rows[0].Close()
    }
    // 其他响应逻辑...
}

5. 额外优化:流式上传大视频

如果你的视频文件体积较大,用ioutil.ReadAll会把整个文件加载到内存,可能导致内存溢出。可以直接把原始的file对象作为Body传给S3,SDK会自动流式上传,节省内存:

params := &s3.PutObjectInput{
    Bucket:        aws.String("yisl"),
    Key:           aws.String(path),
    Body:          file, // 直接用原始文件对象
    ContentLength: aws.Int64(handler.Size),
    ContentType:   aws.String(fileType),
}

按照上面的步骤修复后,应该能解决视频上传的501错误,同时避免nil指针Panic。

内容的提问来源于stack exchange,提问作者user1591668

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:59