Go http發送表單檔案範例。
範例環境:
- Go 1.18
範例
下面範例有兩個API,一為GET|/send
,一為POST|upload
。GET|/send
中會從專案目錄static/image
取得gopher.jpg
檔案,然後將檔案內容寫至http.Request.Body
後透過http.Client.Do()
發送請求給POST|upload
。POST|upload
收到表單請求後將檔案取出存放在專案跟目錄。
注意multipart.NewWriter()
取得的multipart.Writer
要在檔案內容複製到multipart.Writer.CreateFormFile()
建立的io.Writer
就要呼叫multipart.Writer.Close()
關閉。
若在請求建立後才關閉則發送請求時會發生transport connection broken: http: ContentLength=<length-a> with Body length <length-b>
錯誤。而接收端取得檔案時會出現multipart: NextPart: EOF
錯誤。
若在檔案複製到multipart.Writer.CreateFormFile()
建立的io.Writer
前關閉則會出現multipart: can't write to finished part
錯誤。
main.go
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
)
func main() {
http.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
body := new(bytes.Buffer) // the body content writed by multipart.Writer
mw := multipart.NewWriter(body)
// write field "name"
fw, err := mw.CreateFormField("name")
if err != nil {
panic(err)
}
_, err = fw.Write([]byte("John"))
if err != nil {
panic(err)
}
// write field "age"
fw, err = mw.CreateFormField("age")
if err != nil {
panic(err)
}
_, err = fw.Write([]byte("33"))
if err != nil {
panic(err)
}
// write file field "file"
fw, err = mw.CreateFormFile("file", "gopher.jpg")
if err != nil {
panic(err)
}
f, err := os.Open("./static/image/gopher.jpg")
if err != nil {
panic(err)
}
defer f.Close()
_, err = io.Copy(fw, f)
if err != nil {
panic(err)
}
mw.Close() // close multipart.Writer
req, err := http.NewRequest(http.MethodPost, "http://localhost:8080/upload", body)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", mw.FormDataContentType())
client := &http.Client{}
_, err = client.Do(req)
if err != nil {
panic(err)
}
fmt.Fprint(w, "success")
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
})
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
r.ParseMultipartForm(1 << 20) // 1MB
name := r.Form.Get("name") // get value from field "name"
age := r.Form.Get("age") // get value from field "age"
file, header, err := r.FormFile("file") // get file of field "file"
if err != nil {
panic(err)
}
defer file.Close()
buf := bytes.NewBuffer(nil)
_, err = io.Copy(buf, file)
if err != nil {
panic(err)
}
filename := header.Filename
err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
if err != nil {
panic(err)
}
fmt.Printf("name=%v\nage=%v\nfilename=%v\n", name, age, filename)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, "%v uploaded", filename)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
})
http.ListenAndServe(":8080", nil)
}
測試
使用curl輸入curl -X GET "http://localhost:8080/send"
。若執行成功在專案跟目錄會新增一個gopher.jpg
。
$ curl -X GET "http://localhost:8080/send"
success
在console會印出以下:
name=John
age=33
filename=gopher.jpg
沒有留言:
張貼留言