最可靠方式是用 http.NewRequest("DELETE", url, body) 构造请求,设置 header、context 超时,发送后必须 defer resp.Body.Close() 并读取响应体,否则连接复用会阻塞。

用 http.NewRequest 手动构造 DELETE 请求最可靠
Go 标准库没有像 http.Get 或 http.Post 那样直接的 http.Delete(注意:虽有 http.Delete 函数,但它只支持无 body 的简单请求,且无法设 header、timeout 等,实际项目中基本不用)。真正可控的方式是用 http.NewRequest 显式创建 DELETE 方法的请求对象。
常见错误是误以为 http.Delete 能发带 body 或自定义 header 的请求——它不能,调用后会直接返回 405 Method Not Allowed 或服务端静默忽略 body。
- 必须用
http.NewRequest("DELETE", url, body),body可为nil或bytes.NewReader([]byte(...)) - 记得调用
req.Header.Set(...)设置Content-Type(如需传 JSON) - 别忘了用
http.DefaultClient.Do(req)发送,而不是直接丢弃req
DELETE 请求要不要传 body?看接口文档,但 Go 默认允许
HTTP 协议本身不限制 DELETE 带 body(RFC 7231 明确允许),但很多老服务或 Nginx 默认配置会拒绝带 body 的 DELETE。所以不是“能不能”,而是“对方接不接受”。
Go 的 http.Client 完全支持,不会拦截或报错;问题出在服务端或中间件。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 如果接口明确要求 JSON body(如删除多个资源),就传:
bytes.NewReader([]byte(`{"ids":[1,2]}`)) - 若不确定,先试空 body(
nil),再抓包对比 curl 行为:curl -X DELETE -H "Content-Type: application/json" -d '{"ids":[1]}' http://api.example.com/items - Nginx 需显式配置
underscores_in_headers on;和放开 body 限制,否则直接 400
别漏掉 io.ReadAll 和 resp.Body.Close()
DELETE 请求发出后,即使响应体为空,也必须读完并关闭 resp.Body,否则连接会被复用池卡住,后续请求可能超时或阻塞。
典型症状:前几次请求正常,跑一会儿就卡在 Do(),netstat 显示大量 TIME_WAIT 或连接堆积。
- 必须写:
defer resp.Body.Close()(哪怕只是io.ReadAll(resp.Body)后立刻关) - 别只检查
resp.StatusCode就 return —— body 不读,连接不释放 - 用
io.Copy(io.Discard, resp.Body)比io.ReadAll更省内存,适合大响应体
用 context.WithTimeout 控制 DELETE 的超时行为
DELETE 通常涉及数据库删行、清理缓存等操作,耗时可能波动很大。不设超时会导致 goroutine 泄漏或用户长时间等待。
标准 http.Client 的 Timeout 字段对整个请求生效,但更灵活的是用 context 控制单次调用。
- 不要只依赖
client.Timeout,它无法区分 DNS、连接、TLS、读写各阶段 - 推荐:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second),然后req = req.WithContext(ctx) - cancel() 必须调用,尤其在 error 分支里,否则 context 泄漏
- 注意:超时后
resp.Body仍可能非 nil,要先判空再Close()

















