Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST data using the Content-Type multipart/form-data

I'm trying to upload images from my computer to a website using go. Usually, I use a bash script that sends a file and a key to the server:

curl -F "image"=@"IMAGEFILE" -F "key"="KEY" URL 

it works fine, but I'm trying to convert this request into my golang program.

http://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/

I tried this link and many others, but, for each code that I try, the response from the server is "no image sent", and I've no idea why. If someone knows what's happening with the example above.

like image 974
Epitouille Avatar asked Nov 25 '13 23:11

Epitouille


People also ask

What is content type multipart form data?

multipart/form-data [RFC1867] The multipart/form-data content type is intended to allow information providers to express file upload requests uniformly, and to provide a MIME-compatible representation for file upload responses.

How send multipart form data using Fetch?

The basic idea is to use the FormData object (not supported in IE < 10): async function sendData(url, data) { const formData = new FormData(); for(const name in data) { formData. append(name, data[name]); } const response = await fetch(url, { method: 'POST', body: formData }); // ... }


1 Answers

Here's some sample code.

In short, you'll need to use the mime/multipart package to build the form.

package main  import (     "bytes"     "fmt"     "io"     "mime/multipart"     "net/http"     "net/http/httptest"     "net/http/httputil"     "os"     "strings" )  func main() {      var client *http.Client     var remoteURL string     {         //setup a mocked http client.         ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {             b, err := httputil.DumpRequest(r, true)             if err != nil {                 panic(err)             }             fmt.Printf("%s", b)         }))         defer ts.Close()         client = ts.Client()         remoteURL = ts.URL     }      //prepare the reader instances to encode     values := map[string]io.Reader{         "file":  mustOpen("main.go"), // lets assume its this file         "other": strings.NewReader("hello world!"),     }     err := Upload(client, remoteURL, values)     if err != nil {         panic(err)     } }  func Upload(client *http.Client, url string, values map[string]io.Reader) (err error) {     // Prepare a form that you will submit to that URL.     var b bytes.Buffer     w := multipart.NewWriter(&b)     for key, r := range values {         var fw io.Writer         if x, ok := r.(io.Closer); ok {             defer x.Close()         }         // Add an image file         if x, ok := r.(*os.File); ok {             if fw, err = w.CreateFormFile(key, x.Name()); err != nil {                 return             }         } else {             // Add other fields             if fw, err = w.CreateFormField(key); err != nil {                 return             }         }         if _, err = io.Copy(fw, r); err != nil {             return err         }      }     // Don't forget to close the multipart writer.     // If you don't close it, your request will be missing the terminating boundary.     w.Close()      // Now that you have a form, you can submit it to your handler.     req, err := http.NewRequest("POST", url, &b)     if err != nil {         return     }     // Don't forget to set the content type, this will contain the boundary.     req.Header.Set("Content-Type", w.FormDataContentType())      // Submit the request     res, err := client.Do(req)     if err != nil {         return     }      // Check the response     if res.StatusCode != http.StatusOK {         err = fmt.Errorf("bad status: %s", res.Status)     }     return }  func mustOpen(f string) *os.File {     r, err := os.Open(f)     if err != nil {         panic(err)     }     return r } 
like image 167
Attila O. Avatar answered Nov 15 '22 22:11

Attila O.