最直接方式是用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 连接 - 错误只包含网络层或协议错误,HTTP 状态码(如 400、500)需自行检查
resp.StatusCode
resp, err := http.Post("https://www.php.cn/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更精细地控制 - 若需 JSON 数据,手动设置
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.php.cn/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()
处理 POST 返回的 JSON 响应
很多 API 返回 JSON,但容易忽略两个关键点:响应状态码非 2xx 时仍可能有有效 body;resp.Body 是流式读取,只能读一次。
- 先检查
resp.StatusCode,再决定是否解析 body - 用
io.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)
}
常见错误:空 body、415 错误、连接被拒绝
这三个错误高频出现,原因很具体:
-
415 Unsupported Media Type:没设Content-TypeHeader,或值与实际 payload 不匹配(如发 JSON 却设成application/x-www-form-urlencoded) - 空 response body:忘记
defer resp.Body.Close()导致下一次请求复用连接时读到残留数据;或未调用io.ReadAll/json.Decode就结束函数 - connection refused / timeout:目标地址写错(如少个
s写成http://)、服务未启动、防火墙拦截,或http.Client.Timeout设得太短
调试时优先打印 req.URL、req.Header 和 resp.StatusCode,比盲目重试更省时间。










