别手写 http.client 调 openai api,因429不重试、连接不复用、body不close、超时无分层会导致卡死或雪崩;且header/body结构敏感、apibaseurl需配置化、代理与超时须显式设于transport,否则直连失败或泄漏连接。

直接用 net/http 就能对接,但不加控制会在线上崩得无声无息——429 不重试、连接不复用、body 不 close、超时没分层,四个点踩中一个就卡死或雪崩。
为什么别手写 http.Client 调 OpenAI API
看似几行 http.Post 就能发请求,实际线上跑两小时就出问题:
-
429 Too Many Requests返回后直接 panic,没重试逻辑,下游服务瞬间断连 - 每个请求 new 一个
http.Client,Transport没配连接池,TIME_WAIT堆满,Linux 报dial tcp: too many open files - 流式响应(stream=true)下用
json.Unmarshal一次性读整个 body,大回复内存翻倍,GC 频繁卡顿 -
Timeout设成 0 或没设,connect卡住几十秒,read卡住几分钟,全无感知
必须设对的 Header 和 Body 结构
OpenAI API 对字段大小写、嵌套层级、空格极其敏感,错一个就静默失败或返回 400:
-
Authorization必须是Bearer sk-xxx,Bearer后面要有一个空格,sk-开头不能漏,大小写不能错 -
Content-Type必须是application/json,写成text/plain或漏掉,API 会返回空响应但状态码仍是 200 -
messages字段必须是 JSON 数组,至少含一个{"role": "user", "content": "..."},role只能是system/user/assistant - 别硬编码
https://api.openai.com/v1/chat/completions,后续切代理或网关时得全局搜替换,建议抽成配置项APIBaseURL
代理和超时必须显式配在 Transport 上
国内直连基本不可用,但只设环境变量或改 hosts 完全无效:
- Go 默认不读
HTTP_PROXY环境变量,必须手动调http.ProxyFromEnvironment或用http.ProxyURL - 代理必须设在
http.Transport.Proxy字段上,例如:transport.Proxy = http.ProxyURL(&url.URL{Scheme: "http", Host: "127.0.0.1:7890"}) - 如果代理是 HTTPS 类型(如企业网关),
Scheme得写https,否则报unsupported protocol scheme "https" - 超时要分三层:连接超时(
Transport.DialContext)、TLS 握手(Transport.TLSHandshakeTimeout)、读响应(Client.Timeout),缺一不可
response.Body 不 close 是最高频泄漏源
不管 resp.StatusCode 是多少,只要 resp.Body != nil,就必须 defer resp.Body.Close():
- 漏掉它,底层 TCP 连接不会释放,idle 状态卡住,连接池无法复用,实际退化为短连接
- 并发稍高(比如 QPS > 50),几轮下来就触发
too many open files或请求持续 pending - 即使用了
http.DefaultClient,不 close body 也等于白配连接池 - 流式响应(
stream=true)更要小心:不能等整个 body 读完再 close,得边读边处理边 close
真正难的不是发请求,而是让每次请求都可预期、可监控、可回收。连接池怎么调、重试间隔怎么退避、token 数怎么预估、流式响应怎么防阻塞——这些细节不压到代码里,线上就只剩日志里的 timeout 和 connection refused。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











