golang POST data utilisant le type de contenu multipart / form-data

j'essaie de télécharger des images de mon ordinateur sur un site Web en utilisant go. Habituellement, j'utilise un script bash qui envoie un fichier et une clé au serveur:

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

ça marche très bien, mais j'essaie de convertir cette requête en mon programme golang.

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

j'ai essayé ce lien et beaucoup d'autres, mais, pour chaque code que j' essayez, la réponse du serveur est "pas d'image envoyé", et je n'ai aucune idée pourquoi. Si quelqu'un sait ce qui se passe avec l'exemple ci-dessus.

Merci

46
demandé sur Epitouille 2013-11-26 03:42:36

3 réponses

voici un exemple de code.

en bref, vous aurez besoin d'utiliser le mime/multipart paquet pour construire le formulaire.

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
}
88
répondu Attila O. 2018-03-28 20:53:41

en ce qui concerne le poteau d'attila-o, l'en-tête de requête n'a pas la limite puisque l'auteur est déjà fermé.

// after the close, the bounday will be nil.
w.Close()
...
req.Header.Set("Content-Type", w.FormDataContentType())

donc, il devrait fermer après le plateau, je pense.

req.Header.Set("Content-Type", w.FormDataContentType())
w.Close()
0
répondu mttr 2016-04-10 08:28:49

j'ai trouvé ce tutoriel très utile pour clarifier mes confusions sur le téléchargement de fichiers dans Go.

en gros, vous téléchargez le fichier via ajax en utilisant form-data sur un client et utilisez le petit morceau de code Go suivant sur le serveur:

file, handler, err := r.FormFile("img") // img is the key of the form-data
if err != nil {
    fmt.Println(err)
    return
}
defer file.Close()

fmt.Println("File is good")
fmt.Println(handler.Filename)
fmt.Println()
fmt.Println(handler.Header)


f, err := os.OpenFile(handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
    fmt.Println(err)
    return
}
defer f.Close()
io.Copy(f, file)

ici r est *http.Request . P.S. cela stocke simplement le fichier dans le même dossier et n'effectue aucune vérification de sécurité.

0
répondu Salvador Dali 2016-07-03 23:25:16