Golang:恐慌:运行时错误:无效的内存地址或空指针解引用。

huangapple go评论89阅读模式
英文:

Golang: panic: runtime error: invalid memory address or nil pointer dereference

问题

当我上传文件到我的Go应用程序时,遇到了一个恐慌。

 panic: 运行时错误:无效的内存地址或空指针解引用
 /Users/bob/Projects/go/src/github.com/zenazn/goji/web/middleware/recoverer.go:24 (0xbaf5b)
    func.006: debug.PrintStack()
 /usr/local/go/src/pkg/runtime/panic.c:248 (0x1043d)
    panic: runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
 /usr/local/go/src/pkg/runtime/panic.c:552 (0x10eed)
    panicstring: runtime·panic(err);
 /usr/local/go/src/pkg/runtime/os_darwin.c:454 (0xfb8e)
    sigpanic: runtime·panicstring("invalid memory address or nil pointer dereference");
 /usr/local/go/src/pkg/mime/multipart/multipart.go:223 (0xb6801)
    (*Reader).NextPart: if r.currentPart != nil {
 /Users/bob/Projects/go/src/github.com/app/controllers/company_sheet_controller.go:32 (0x2ee18)
    NewCompanySheet: part, err := mr.NextPart()
 /usr/local/go/src/pkg/net/http/server.go:1235 (0x44f00)
    HandlerFunc.ServeHTTP: f(w, r)
 /Users/bob/Projects/go/src/github.com/zenazn/goji/web/router.go:113 (0x6bc0a)

这个方法处理来自多部分表单的上传,提取文件内容和边界数据。请求的r.FormFile方法用于设置文件和头部。为了从POST请求中获取额外的数据,我使用了r.MultipartReader。从错误描述中我看到,在使用r.FormFile时,r已经被声明为ParseMultipartForm。当我单独执行不同的请求方法时,没有出现错误。r.FormFiler.MultipartReader在隔离的情况下工作正常。我不能混合使用这两种请求方法吗?

func Upload(r *http.Request) {
  file, header, err := r.FormFile("file")
  ErrorCheck(err)

  mr, err := r.MultipartReader()
  ErrorCheck(err)
  part, err := mr.NextPart()
  ErrorCheck(err)

  var b bytes.Buffer
  io.CopyN(&b, part, int64(1<<20))
  fmt.Println(b.String())
  defer file.Close()
}
英文:

When uploading a file to my go app, I encounter a panic.

 panic: runtime error: invalid memory address or nil pointer dereference
 /Users/bob/Projects/go/src/github.com/zenazn/goji/web/middleware/recoverer.go:24 (0xbaf5b)
    func.006: debug.PrintStack()
 /usr/local/go/src/pkg/runtime/panic.c:248 (0x1043d)
    panic: runtime&#183;newstackcall(d-&gt;fn, (byte*)d-&gt;args, d-&gt;siz);
 /usr/local/go/src/pkg/runtime/panic.c:552 (0x10eed)
    panicstring: runtime&#183;panic(err);
 /usr/local/go/src/pkg/runtime/os_darwin.c:454 (0xfb8e)
    sigpanic: runtime&#183;panicstring(&quot;invalid memory address or nil pointer dereference&quot;);
 /usr/local/go/src/pkg/mime/multipart/multipart.go:223 (0xb6801)
    (*Reader).NextPart: if r.currentPart != nil {
 /Users/bob/Projects/go/src/github.com/app/controllers/company_sheet_controller.go:32 (0x2ee18)
    NewCompanySheet: part, err := mr.NextPart()
 /usr/local/go/src/pkg/net/http/server.go:1235 (0x44f00)
    HandlerFunc.ServeHTTP: f(w, r)
 /Users/bob/Projects/go/src/github.com/zenazn/goji/web/router.go:113 (0x6bc0a)

This method handles an upload from a multipart form, extracting the file contents and boundary data. The r.FormFile method on request is used to set file and header. And in order to pull the additional data from the post, I use r.MultipartReader. From the error description I see r is already declared as ParseMultipartForm when using r.FormFile. When executing the function with the different request methods individually, I receive no errors. r.FormFile and r.MultipartReader work fine isolated. Am I unable to mix the two request methods?

func Upload(r *http.Request) {
  file, header, err := r.FormFile(&quot;file&quot;)
  ErrorCheck(err)

  mr, err := r.MultipartReader()
  ErrorCheck(err)
  part, err := mr.NextPart()
  ErrorCheck(err)

  var b bytes.Buffer
  io.CopyN(&amp;b, part, int64(1&lt;&lt;20))
  fmt.Println(b.String())
  defer file.Close()
}

答案1

得分: 2

你在函数的开头调用了FormFile()。

这会调用ParseMultipartForm()(参见Request.FormFile),它会填充你的http.Request的MultipartForm字段。

现在,MultipartReader()的文档说明如果你想将数据作为流进行处理,应该使用MultipartReader() 而不是 ParseMultipartForm()。

源代码可以看出,如果MultipartForm字段已经设置,MultipartReader()会返回一个错误。

所以回答你的问题:不,你不能在同一个请求中同时使用这两个函数。

另外,你的

defer file.Close()

应该在检查FormFile()是否返回错误之后立即执行,否则在函数发生恐慌时,文件将在垃圾回收之前不会被关闭。

英文:

You are calling FormFile() at the beginning of your function.

This calls ParseMultipartForm() (see Request.FormFile) which populates the MultipartForm field of your http.Request.

Now the documentation for MultipartReader() states that you should use MultipartReader() instead of ParseMultipartForm() if you want to process the data as stream.

Looking at the source MultipartReader() returns an error if the MultipartForm field was already set.

So to answer your question: No, you can't use both functions for the same request.

Also your

defer file.Close()

should be right after you checked for an error from FormFile(), otherwise the file won't be closed before Garbage Collection, when your function panics.

1: http://golang.org/pkg/net/http/#Request.FormFile "Request.FormFile"
2: http://golang.org/pkg/net/http/#Request "http.Request"
3: http://golang.org/pkg/net/http/#Request.MultipartReader "MultipartReader"
4: http://golang.org/src/net/http/request.go?s=10494:10556#L286 "source of MultipartReader&#40;&#41;"

huangapple
  • 本文由 发表于 2014年12月28日 14:31:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/27674200.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定