我一直在處理一個問題,我必須將一個io.Reader實體作為引數放入由 api 提供的作為端點的函式。我需要做的任務是將本地檔案夾上傳到公司的云存盤。
func (s *server) uploadFileToPutIo(w http.ResponseWriter, r *http.Request) {
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
oauthClient := oauth2.NewClient(context.TODO(), tokenSource)
client := putio.NewClient(oauthClient)
var testIO io.Reader // ?
upload, err := client.Files.Upload(context.TODO(), testIO, "test", 0)
if err != nil {
log.Fatal(err)
}
fmt.Println(upload.File)
sendResponse(w, []byte("successful"), http.StatusOK)
}
當我/upload在 POST 方法下向該端點發出請求時。我收到以下錯誤。
2021/12/01 18:28:47 http: panic serving 127.0.0.1:61057: runtime error: invalid memory address or nil pointer dereference
goroutine 8 [running]:
net/http.(*conn).serve.func1(0xc000108d20)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:1804 0x153
panic(0x1390ae0, 0x164fdd0)
/usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:971 0x499
io.copyBuffer(0x1462700, 0xc000026360, 0x0, 0x0, 0xc000170000, 0x8000, 0x8000, 0x0, 0x0, 0x13d5e01)
/usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:423 0x10b
io.Copy(...)
/usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:382
github.com/putdotio/go-putio/putio.(*FilesService).Upload(0xc000010088, 0x1468390, 0xc00001c088, 0x0, 0x0, 0x13ef46f, 0x6, 0x0, 0x170d108, 0x90, ...)
/Users/barisertas/go/pkg/mod/github.com/putdotio/go-putio/putio@v0.0.0-20200123120452-16d982cac2b8/files.go:235 0x187
main.(*server).uploadFileToPutIo(0xc000010028, 0x1467d60, 0xc00014a2a0, 0xc000154500)
/Users/barisertas/workspace/mini-project/api/handler.go:79 0xe5
net/http.HandlerFunc.ServeHTTP(0xc000012db0, 0x1467d60, 0xc00014a2a0, 0xc000154500)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2049 0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000144000, 0x1467d60, 0xc00014a2a0, 0xc000154300)
/Users/barisertas/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 0xd3
net/http.serverHandler.ServeHTTP(0xc00014a000, 0x1467d60, 0xc00014a2a0, 0xc000154300)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2867 0xa3
net/http.(*conn).serve(0xc000108d20, 0x1468400, 0xc00005e300)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:1932 0x8cd
created by net/http.(*Server).Serve
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2993 0x39b
2021/12/01 18:28:47 http: panic serving 127.0.0.1:61059: runtime error: invalid memory address or nil pointer dereference
goroutine 11 [running]:
net/http.(*conn).serve.func1(0xc000108dc0)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:1804 0x153
panic(0x1390ae0, 0x164fdd0)
/usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:971 0x499
io.copyBuffer(0x1462700, 0xc000026400, 0x0, 0x0, 0xc000198000, 0x8000, 0x8000, 0x0, 0x0, 0x13d5e01)
/usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:423 0x10b
io.Copy(...)
/usr/local/Cellar/go/1.16.6/libexec/src/io/io.go:382
github.com/putdotio/go-putio/putio.(*FilesService).Upload(0xc0000100c8, 0x1468390, 0xc00001c088, 0x0, 0x0, 0x13ef46f, 0x6, 0x0, 0x170d108, 0x90, ...)
/Users/barisertas/go/pkg/mod/github.com/putdotio/go-putio/putio@v0.0.0-20200123120452-16d982cac2b8/files.go:235 0x187
main.(*server).uploadFileToPutIo(0xc000010028, 0x1467d60, 0xc00014a380, 0xc000154800)
/Users/barisertas/workspace/mini-project/api/handler.go:79 0xe5
net/http.HandlerFunc.ServeHTTP(0xc000012db0, 0x1467d60, 0xc00014a380, 0xc000154800)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2049 0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000144000, 0x1467d60, 0xc00014a380, 0xc000154600)
/Users/barisertas/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 0xd3
net/http.serverHandler.ServeHTTP(0xc00014a000, 0x1467d60, 0xc00014a380, 0xc000154600)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2867 0xa3
net/http.(*conn).serve(0xc000108dc0, 0x1468400, 0xc00005e580)
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:1932 0x8cd
created by net/http.(*Server).Serve
/usr/local/Cellar/go/1.16.6/libexec/src/net/http/server.go:2993 0x39b
這是我嘗試使用的函式的檔案:
// Upload reads from given io.Reader and uploads the file contents to Put.io
// servers under directory given by parent. If parent is negative, user's
// preferred folder is used.
//
// If the uploaded file is a torrent file, Put.io will interpret it as a
// transfer and Transfer field will be present to represent the status of the
// tranfer. Likewise, if the uploaded file is a regular file, Transfer field
// would be nil and the uploaded file will be represented by the File field.
//
// This method reads the file contents into the memory, so it should be used for
// <150MB files.
func (f *FilesService) Upload(ctx context.Context, r io.Reader, filename string, parent int64) (Upload, error) {
if filename == "" {
return Upload{}, fmt.Errorf("filename cannot be empty")
}
var buf bytes.Buffer
mw := multipart.NewWriter(&buf)
// negative parent means use user's preferred download folder.
if parent >= 0 {
err := mw.WriteField("parent_id", itoa(parent))
if err != nil {
return Upload{}, err
}
}
formfile, err := mw.CreateFormFile("file", filename)
if err != nil {
return Upload{}, err
}
_, err = io.Copy(formfile, r)
if err != nil {
return Upload{}, err
}
err = mw.Close()
if err != nil {
return Upload{}, err
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/upload", &buf)
if err != nil {
return Upload{}, err
}
req.Header.Set("Content-Type", mw.FormDataContentType())
var response struct {
Upload
}
_, err = f.client.Do(req, &response)
if err != nil {
return Upload{}, err
}
return response.Upload, nil
}
我對將io.Reader實體放入函式感到困惑。io.Reader在這種情況下,如何正確放置該功能。創建后只是一個實體,如下所示:
var testIO io.Reader還是應該做一些額外的操作?
uj5u.com熱心網友回復:
runtime error: invalid memory address or nil pointer dereference
你肯定知道,這是因為你已經宣告了 anio.Reader但你還沒有設定它的值,所以它仍然等于介面的默認值,即nil.
var testIO io.Reader // ?
傳遞io.Readerto 的目的Upload是提供要上傳的資料。通過傳遞io.Reader,任意資料源可以提供任意數量的位元組,不受記憶體可用性的限制(不像[]byte,它需要在上傳之前將所有資料保存在記憶體中)。 io.Reader通常用于為這種“流式”操作提供資料。
Upload reads from given io.Reader and uploads the file contents
那io.Reader應該是要上傳的資料的來源。
io.Reader可能是來自os.Open().
但它可以是任何滿足條件的東西io.Reader——例如,它也可以是bytes.Buffer.
它甚至可能是更深奧的東西,比如GetObject對來自 AWS 的流行 S3 服務的API 呼叫的結果,它也回傳io.ReadCloser滿足io.Reader.
io.Reader是 Go 介面如何允許獨立庫相互連接的一個很好的例子。你使用的 SDK 并不關心io.Reader它傳遞了什么;滿足該值就足夠了,這是io.Reader在編譯時強制執行的要求。您可以將任何滿足的東西傳遞給它io.Reader,并且介面型別保證Upload()能夠正確處理它。
Upload需要一個io.Reader. 如果您想傳遞諸如*os.Filefromos.Open或io.ReadCloserfrom 之類的東西,例如 S3 GetObject,那會起作用,因為io.ReadCloser滿足io.Reader. 但是,由于不Upload接受,您可以確信它只會呼叫該介面中定義的函式。在被呼叫后,您必須自己進行任何關閉操作。io.Readerio.ReadCloserUpload
確保花時間了解如何io.Reader使此函式的輸入保持開放式,同時還要具體說明它所期望的介面。這是 Go 中最重要的概念之一。
uj5u.com熱心網友回復:
這個:
var testIO io.Reader
相當于:
testIO := io.Reader(nil)
所以這就是為什么您對空指標參考感到恐慌的原因:
2021/12/01 18:28:47 http: panic serving 127.0.0.1:61059: runtime error: invalid memory address or nil pointer dereference
goroutine 11 [running]:
一個io.Reader是一個介面,它允許一個通過一般值,只要它們實作的介面(即,實作的Read方法)。
由于您正在上傳檔案,因此您的位元組流應該來自作業系統檔案。os.File實作了正確的Read方法 - 所以是兼容的io.Reader。
所以嘗試:
f, err := os.Open(uploadFilePath)
if err != nil { /* ... */ }
upload, err := client.Files.Upload(context.TODO(), f, "test", 0)
uj5u.com熱心網友回復:
當您定義一個變數時,它的初始值是該zero value型別的。io.Reader是一個介面,它的零值是nil。因此 nil pointer dereference error. 只需io.Reader在將其傳遞給 Upload 之前對其進行初始化:
file, err := os.Open("path/to/file")
// if err != nil { ... }
upload, err := client.Files.Upload(context.TODO(), file, "test", 0)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/371074.html
