最简写法是直接调用 http.NewRequest("PUT", url, body),需手动设 Content-Type;http.Put 默认设错 Content-Type 且不支持自定义 header,而 NewRequest 完全可控。

用 http.NewRequest 构造 PUT 请求最简写法
直接调用 http.NewRequest 并传入 "PUT" 方法名,是最可控的方式。它不自动设置 Content-Type 或处理 body 编码,适合需要精细控制的场景。
常见错误是忽略 body 参数必须为 io.Reader 类型——传 nil 表示空体,传字符串需先转成 strings.NewReader(...),否则请求发不出或服务端收不到数据。
-
body为nil:构造无 body 的 PUT(如纯资源状态更新) -
body为strings.NewReader(`{"name":"foo"}`):发送 JSON 字符串 - 别忘了手动设置
req.Header.Set("Content-Type", "application/json"),NewRequest不会帮你设
为什么不用 http.Put?它和 NewRequest 的关键区别在哪
http.Put 是封装好的快捷函数,只接受 string 类型的 body,内部会自动调用 strings.NewReader 并设置 Content-Type: application/x-www-form-urlencoded ——这个默认值在大多数 API 场景下是错的。
比如你传 JSON 字符串给 http.Put,它不会改 Content-Type,服务端大概率返回 415 Unsupported Media Type。而 NewRequest 把 header 和 body 完全交给你控制,没有隐藏行为。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
立即学习“go语言免费学习笔记(深入)”;
-
http.Put(url, "application/json", strings.NewReader(data))❌ 第二个参数被忽略,实际仍是x-www-form-urlencoded -
http.NewRequest("PUT", url, strings.NewReader(data))✅ header、body、method 全由你定
带 JSON body 的 PUT 完整示例(含错误处理)
真正上线用的代码得处理网络超时、连接失败、非 2xx 响应等。别只看 Do 是否 panic,HTTP 状态码才是业务成败的关键。
client := &http.Client{
Timeout: 10 * time.Second,
}
req, err := http.NewRequest("PUT", "https://api.example.com/users/123", strings.NewReader(`{"name":"alice"}`))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer xxx")
<p>resp, err := client.Do(req)
if err != nil {
log.Fatal(err) // 如 net/http: request canceled
}
defer resp.Body.Close()</p><p>if resp.StatusCode < 200 || resp.StatusCode >= 300 {
log.Printf("PUT failed: %d %s", resp.StatusCode, resp.Status)
// 这里通常要读 resp.Body 做错误解析
}
容易被忽略的坑:body 被读取后不可重用
如果你把同一个 strings.NewReader 或 bytes.Buffer 多次塞进不同 NewRequest,第二次会发空 body ——因为 reader 已被第一次 Do 消耗完。调试时看到“请求成功但数据没变”,十有八九是这问题。
- 每次请求都新建
strings.NewReader,别复用 - 如果 body 来自文件或大对象,用
os.Open而不是os.ReadFile+strings.NewReader,避免内存暴涨 - 测试时用
httptest.NewServer拦截请求,打印req.Body内容确认是否为空
Golang 的 PUT 不难,难在 HTTP 协议细节藏得深:header 默认值、body 生命周期、状态码语义,这些地方一松懈就掉进生产环境排查两小时的坑。

















