最直接方式是用http.Post发送表单数据,但仅适合调试;生产环境应使用自定义http.Client设置超时、Header等;需检查状态码再解析JSON响应,避免415、空body、连接拒绝等常见错误。
http.Post 发送简单表单数据最直接的方式是调用 http.Post,它封装了常见场景:设置 Content-Type: application/x-www-form-urlencoded,自动编码键值对。
但要注意它不支持自定义超时、Header 或重试逻辑,仅适合调试或极简需求。
io.Reader,所以常用 strings.NewReader 包裹 url.Values.Encode() 结果*http.Response 必须手动关闭,否则会泄漏 HTTP 连接resp.StatusCode
resp, err := http.Post("https://www./link/dc076eb055ef5f8a60a41b6195e9f329", "application/x-www-form-urlencoded", strings.NewReader("name=alice&age=30"))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close() // 必须加
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
http.Client 自定义 POST 请求生产环境应使用 http.Client 实例,便于控制超时、复用连接、注入 Header 和处理重定向。
默认的 http.DefaultClient 没有设置超时,长时间阻塞会导致 goroutine 泄漏。
Timeout 字段,推荐用 context.WithTimeout 更精细地控制Content-Type: application/json,并用 json.Marshal 序列化multipart.Writer,不能直接传 JSON 字节流client := &http.Client{
Timeout: 10 * time.Second,
}
data := map[string]string{"name": "bob", "city": "shanghai"}
jsonBytes, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://www./link/dc076eb055ef5f8a60a41b6195e9f329", bytes.NewBuffer(jsonBytes))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer abc123")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
很多 API 返回 JSON,但容易忽略两个关键点:响应状态码非 2xx 时仍可能有有效 body;resp.Body 是流式读取,只能读一次。
resp.StatusCode,再决定是否解析 bodyio.ReadAll 一次性读完,避免后续调用 json.Unmarshal 时因 body 已关闭或耗尽而失败json.NewDecoder(resp.Body) 流式解码,但需确保提前检查状态码if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
log.Printf("API error %d: %s", resp.StatusCode, string(body))
return
}
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
log.Fatal(err)
}
这三个错误高频出现,原因很具体:
415 Unsupported Media Type:没设 Content-Type Header,或值与实际 payload 不匹配(如发 JSON 却设成 application/x-www-form-urlencoded)defer resp.Body.Close() 导致下一次请求复用连接时读到残留数据;或未调用 io.ReadAll / json.Decode 就结束函数s 写成 http://)、服务未启动、防火墙拦截,或 http.Client.Timeout 设得太短调试时优先打印 req.URL、req.Header 和 resp.StatusCode,比盲目重试更省时间。