我正在try 使用go将图像从我的电脑上传到一个网站.通常,我使用bash脚本将文件和密钥发送到服务器:

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

它工作得很好,但我正在try 将此请求转换为我的golang程序.

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

我try 了这个链接和许多其他链接,但是,对于我try 的每个代码,来自服务器的响应都是"没有发送图像",我不知道为什么.如果有人知道上面的例子发生了什么.

推荐答案

以下是一些示例代码.

简而言之,您需要使用mime/multipart package来构建表单.

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
}

Go相关问答推荐

Google OAuth2没有刷新令牌

如何描述OpenAPI规范中围棋的数据类型.JSON?

将类型定义为泛型类型实例化

在GO中创建[]字符串类型的变量

Go中的Slice[:1][0]与Slice[0]

关于如何使用 Service Weaver 设置多个不同侦听器的问题

go测试10m后如何避免超时

Cypher 查找(多个)最低 node

在golang中以JSON格式获取xwwwformurlencoded请求的嵌套键值对

正确的 shell 程序进入 golang alpine docker 容器的入口点?

同一文件上的多个 Arrow CSV 阅读器返回 null

Yocto 无法交叉编译 GoLang Wails 应用程序

GoLang:net.LookupHost 返回重复的 ips

Golang crypto/rand 线程安全吗?

使用 Go 解组 SOAP 消息

为什么 `append(x[:0:0], x...)` 将切片复制到 Go 中的新后备数组中?

在 Golang 模板中计算时间/持续时间

使用 delve 在容器中调试 Golang:container_linux.go:380:启动容器进程导致:exec:/dlv:stat /dlv:没有这样的文件或目录

go mod tidy 错误消息:但是 go 1.16 会 Select

如何将实际上是类型为 reflect.Int32 的类型切片的 interface{} 转换为 int32 的切片?