
本文介绍如何在 Go 中构建 multipart/form-data 请求,向 Zamzar 等 API 服务上传二进制文件(如 []byte)并同时提交字符串字段(如 target_format),涵盖 multipart.Writer 的正确用法、请求头设置及常见陷阱。
本文介绍如何在 go 中构建 multipart/form-data 请求,向 zamzar 等 api 服务上传二进制文件(如 `[]byte`)并同时提交字符串字段(如 `target_format`),涵盖 `multipart.writer` 的正确用法、请求头设置及常见陷阱。
在 Go 中模拟 curl -F 表单上传(即 multipart/form-data),不能直接复用 http.NewRequest("GET", ...) —— 首先需将请求方法改为 "POST",其次必须手动构造符合 RFC 7578 规范的多部分请求体。关键在于使用标准库的 mime/multipart 包,而非 JSON 或普通表单编码。
以下是一个完整、健壮的实现示例(假设你已持有图像字节数据 imageBytes []byte):
package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
)
func uploadToZamzar(imageBytes []byte) error {
// 1. 创建内存缓冲区和 multipart writer
var buf bytes.Buffer
mpw := multipart.NewWriter(&buf)
// 2. 添加文件字段:注意 CreateFormFile 第二个参数是服务端看到的文件名(非路径)
fileWriter, err := mpw.CreateFormFile("source_file", "portrait.gif")
if err != nil {
return fmt.Errorf("failed to create form file: %w", err)
}
if _, err := io.Copy(fileWriter, bytes.NewReader(imageBytes)); err != nil {
return fmt.Errorf("failed to write file data: %w", err)
}
// 3. 添加普通文本字段
if err := mpw.WriteField("target_format", "png"); err != nil {
return fmt.Errorf("failed to write target_format field: %w", err)
}
// 4. 关闭 writer,确保边界符(boundary)写入缓冲区末尾
if err := mpw.Close(); err != nil {
return fmt.Errorf("failed to close multipart writer: %w", err)
}
// 5. 构建 POST 请求(⚠️ 注意:方法必须是 POST,不是 GET)
req, err := http.NewRequest("POST", "https://sandbox.zamzar.com/v1/jobs", &buf)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
// 6. 设置 Basic Auth 和 Content-Type(必须使用 mpw.FormDataContentType())
req.SetBasicAuth("user", "pass")
req.Header.Set("Content-Type", mpw.FormDataContentType())
// 7. 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("HTTP request failed: %w", err)
}
defer resp.Body.Close()
fmt.Printf("Upload completed with status: %s\n", resp.Status)
return nil
}✅ 关键注意事项:
-
请求方法必须为
POST:原代码中误用"GET",会导致 Zamzar 返回 405 Method Not Allowed; -
Content-Type必须由mpw.FormDataContentType()提供:它会动态生成带唯一 boundary 的 header(如multipart/form-data; boundary=xyz123),手动拼写极易出错; -
文件名不含路径:
CreateFormFile("source_file", "portrait.gif")中的"portrait.gif"是逻辑文件名,Zamzar 仅依赖此名称识别类型,无需真实路径; -
显式关闭
mpw:否则 boundary 不会写入,服务端无法解析 multipart; -
错误处理建议:生产环境应增加超时控制(通过
http.Client.Timeout或context.WithTimeout)和重试逻辑。
该模式适用于所有兼容 curl -F 的 RESTful 文件上传接口(如 Cloudinary、ImgBB、Zamzar),是 Go 标准库处理表单上传的推荐实践。

















