必须用 multipart.Writer 构造请求体:创建 bytes.Buffer,用 multipart.NewWriter 写字段和文件,调用 w.Close(),设置 req.Header.Set("Content-Type", w.FormDataContentType())。
用
上传文件会失败,必须用
直接调用
并传入
是行不通的——它只会把原始
字节
当纯文本发过去,服务器端收不到
的边界(boundary)和字段结构。正确做法是手动构造 multipart 请求体。
关键点在于:先创建
,再用
写入字段和文件数据,最后把
作为请求体发送,并设置正确的
头(含 boundary)。
会自动生成并管理 boundary,不能硬
编码
写完所有字段后必须调用
,否则 boundary 结尾缺失,服务端解析失败
是必须的,不能手写
上传单个文件时如何设置文件名和字段名
服务端(比如 Gin 或标准
)依赖
和
的参数来识别字段名和文件元信息。字段名(
)、文件名(
)都由你控制,不是自动推断的。
常见错误是把文件内容当成字符串传给
,结果服务端收到的是明文内容而非文件流。
立即学习
“
go语言免费学习笔记(深入)
”;
php版微信js-sdk支付接口类
php版微信js-sdk支付接口类
下载
普通表单字段用
文件字段必须用
获取
,再把文件内容写进去
字段名(如
)要和服务端
中的键完全一致
上传多个文件或混合字段的完整示例
注意:
的第一个参数是字段名(可复用,如都用
实现多文件),第二个是客户端看到的文件名(影响
)。
服务端解析时容易忽略的边界条件
Go
标准库
要求在读取 multipart 前调用
,否则
为
。而且这个方法会一次性把全部文件读进内存或临时磁盘,不设限可能被恶意大文件打爆内存。
务必设置合理上限:
如果只处理小文件且想避免磁盘临时文件,可设
,超过才落盘
返回的是
,不是单个值
读取文件内容前需用
获得
,别漏掉
boundary 不匹配、没调
、服务端没调
——这三个问题占了调试失败的八成以上。
http.Postmultipart.Writerhttp.Postbytes.NewReadermultipart/form-databytes.Buffermultipart.NewWriterBuffer.Bytes()Content-Typemultipart.Writerw.Close()req.Header.Set("Content-Type", w.FormDataContentType())multipart/form-data; boundary=xxxhttp.Request.ParseMultipartFormmultipart.Writer.WriteFieldmultipart.Writer.CreateFormFilefilereport.pdfWriteFieldw.WriteField("username", "alice")w.CreateFormFile("file", "report.pdf")io.Writer"file"r.FormFile("file")package main
import (
"bytes"
"io"
"mime/multipart"
"net/http"
)
func uploadFiles() error {
buf := &bytes.Buffer{}
w := multipart.NewWriter(buf)
// 写普通字段
if err := w.WriteField("project_id", "123"); err != nil {
return err
}
// 写第一个文件
fw1, err := w.CreateFormFile("files", "a.txt")
if err != nil {
return err
}
io.WriteString(fw1, "content of a.txt")
// 写第二个文件
fw2, err := w.CreateFormFile("files", "b.json")
if err != nil {
return err
}
io.WriteString(fw2, `{"id": 42}`)
// 关键:关闭 writer,生成结尾 boundary
w.Close()
req, err := http.NewRequest("POST", "http://localhost:8080/upload", buf)
if err != nil {
return err
}
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}CreateFormFile"files"Header.Get("Filename")r.ParseMultipartFormr.MultipartFormnilr.ParseMultipartForm(32 (32MB)MaxMemoryr.MultipartForm.File["files"][]*multipart.FileHeaderheader.Open()io.ReadCloserClose()w.Close()ParseMultipartForm