-
-
Save mattetti/5914158 to your computer and use it in GitHub Desktop.
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io" | |
"log" | |
"mime/multipart" | |
"net/http" | |
"os" | |
"path/filepath" | |
) | |
// Creates a new file upload http request with optional extra params | |
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { | |
file, err := os.Open(path) | |
if err != nil { | |
return nil, err | |
} | |
defer file.Close() | |
body := &bytes.Buffer{} | |
writer := multipart.NewWriter(body) | |
part, err := writer.CreateFormFile(paramName, filepath.Base(path)) | |
if err != nil { | |
return nil, err | |
} | |
_, err = io.Copy(part, file) | |
for key, val := range params { | |
_ = writer.WriteField(key, val) | |
} | |
err = writer.Close() | |
if err != nil { | |
return nil, err | |
} | |
req, err := http.NewRequest("POST", uri, body) | |
req.Header.Set("Content-Type", writer.FormDataContentType()) | |
return req, err | |
} | |
func main() { | |
path, _ := os.Getwd() | |
path += "/test.pdf" | |
extraParams := map[string]string{ | |
"title": "My Document", | |
"author": "Matt Aimonetti", | |
"description": "A document with all the Go programming language secrets", | |
} | |
request, err := newfileUploadRequest("https://google.com/upload", extraParams, "file", "/tmp/doc.pdf") | |
if err != nil { | |
log.Fatal(err) | |
} | |
client := &http.Client{} | |
resp, err := client.Do(request) | |
if err != nil { | |
log.Fatal(err) | |
} else { | |
body := &bytes.Buffer{} | |
_, err := body.ReadFrom(resp.Body) | |
if err != nil { | |
log.Fatal(err) | |
} | |
resp.Body.Close() | |
fmt.Println(resp.StatusCode) | |
fmt.Println(resp.Header) | |
fmt.Println(body) | |
} | |
} |
@sebnyberg Hello, just wanted to understand about the comment "This operation will block until both the formWriter...". Could you please explain, thank you!
@sebnyberg Hello, just wanted to understand about the comment "This operation will block until both the formWriter...". Could you please explain, thank you!
Sure. The request reads from the provided reader until it returns io.EOF. For an io.Pipe, the reader-end will return io.EOF after the write-end is closed. That's what is meant by "blocking". If the bodyWriter is not closed, the the request will last forever (until conn timeout).
https://pkg.go.dev/io#PipeWriter.Close
Closing the formWriter isn't strictly necessary to send the request. However, the formWriters Close() writes a trailer to the multipart message that is required for the request to be valid.
@sebnyberg Thank you very much! :)
If uploading specific format like gzip or server expect content other than octet-stream, better to use writer.CreatePart
instead of formWriter.CreateFormFile
part, err := writer.CreatePart(textproto.MIMEHeader{
"Content-Type": []string{"application/x-gzip"},
"Content-Disposition": []string{fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
"file", fi.Name())},
})
Really useful, it works