Go发送HTTP表单应使用url.Values+PostForm;需自定义Header时用NewRequest+Encode;文件上传必须用multipart.Writer并调Close。

Go 语言发送 HTTP 表单,别用 json.Marshal 直接丢给 http.Post —— 那发出去的是 raw JSON,不是 application/x-www-form-urlencoded,后端收不到 form 字段。
用 url.Values 构建表单数据,再调用 PostForm
这是最直接、最安全的方式,适用于标准键值对提交(比如登录、注册):
-
url.Values本质是map[string][]string,自动做 URL 编码 -
http.PostForm内部会设置正确的Content-Type: application/x-www-form-urlencoded - 不需要手动拼 query string,也不用管空格变
+、中文变%E4%BD%A0
data := url.Values{}
data.Set("username", "zhangsan")
data.Set("email", "zhang@ex.com")
resp, err := http.PostForm("https://api.example.com/login", data)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
需要自定义 Header 或复用 Client?用 http.NewRequest + SetBasicAuth 或 Header.Set
当你要加认证头、超时控制、或复用 http.Client 时,PostForm 就不够用了:
- 必须手动调
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - 不能漏掉
strings.NewReader(data.Encode())——Encode()才生成最终的表单字符串 - 如果忘了设
Content-Type,某些后端(如 Gin 的c.ShouldBind())会直接忽略 body
data := url.Values{"username": {"lisi"}, "token": {"abc123"}}
req, _ := http.NewRequest("POST", "https://api.example.com/submit", strings.NewReader(data.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("X-App-Version", "1.2.0")
<p>client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
上传文件 + 表单字段?别硬套 PostForm,改用 multipart/form-data
PostForm 和 url.Values 完全不支持文件上传。强行把文件内容塞进 url.Values 只会导致乱码或截断:
立即学习“go语言免费学习笔记(深入)”;
- 必须用
mime/multipart创建 writer - 字段名要和后端约定一致(比如
file、description) - 注意
Close()必须调用,否则 boundary 结束符缺失,后端解析失败 - 常见错误:忘记
writer.WriteField设置普通字段,只传了文件
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
writer.WriteField("title", "report.pdf")
file, _ := os.Open("report.pdf")
defer file.Close()
part, _ := writer.CreateFormFile("file", "report.pdf")
io.Copy(part, file)
writer.Close() // 关键:不调这个,后端收不到完整数据
<p>req, _ := http.NewRequest("POST", "<a href="https://www.php.cn/link/f142c6067e6345134c6728f299cf4c1e">https://www.php.cn/link/f142c6067e6345134c6728f299cf4c1e</a>", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
表单提交看着简单,但 Content-Type 错一位、Encode() 忘一次、Close() 漏一回,后端就收不到字段——这些都不是 Go 的问题,是 HTTP 协议本身的要求。写的时候多看一眼抓包里的 Request Headers 和 Raw Body,比查文档更快。


















