应全局复用一个resty.Client实例,避免每次新建连接;用SetRetryCount+SetRetryDelay控制重试但不重试4xx错误;通过SetResult/SetError自动反序列化响应;统一SetHeader注入通用头;分层设置超时(连接、读写、总耗时);第三方调用需配置可变、错误可溯、超时可控、开关可切。

用 go-resty 封装第三方请求,别直接裸写 http.Client
直接用 net/http 写第三方调用,短期内能跑通,但很快会暴露问题:超时控制分散、重试逻辑重复、错误码解析不统一、Header 和 Auth 配置每次都要手写。go-resty 的价值不是“多一个依赖”,而是把这类重复劳动标准化。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 全局复用一个
resty.Client实例(比如挂到goframe的容器里),避免每次请求都新建连接 - 用
SetRetryCount()+SetRetryDelay()控制基础重试,但别对 4xx 错误重试(比如401 Unauthorized或404 Not Found) - 用
SetResult()和SetError()绑定结构体,让成功响应和错误响应自动反序列化,而不是手动json.Unmarshal - 通过
SetHeader或SetCommonHeader统一注入Authorization、User-Agent等通用头,避免每个接口都写一遍
错误处理必须区分 HTTP 层和业务层
第三方 API 返回的 500 Internal Server Error 和你本地网络超时,根本不是一类问题;同样,对方返回 200 OK 但 body 里是 {"code": 40001, "msg": "token expired"},也不能当成成功处理。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 先检查
resp.StatusCode是否在200–299范围,否则走 HTTP 错误分支(如连接失败、5xx、408) - 再检查响应体里的业务字段(比如
code != 0或status == "fail"),这部分要映射成自定义 error 类型,比如ErrThirdPartyAuthFailed - 不要用字符串比较判断错误,用结构体字段 +
errors.Is(),方便后期 mock 和测试 - 日志里至少记录
resp.Request.URL、resp.StatusCode、resp.Status和业务code,缺一不可
超时设置要分层:连接、读写、总耗时
只设一个 Timeout 很容易误伤——比如第三方 DNS 解析慢导致连接卡住,但你设的 5s 总超时还没到,结果整个请求被拖死。go-resty 支持细粒度控制,必须用起来。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
SetTimeout(5 * time.Second)是总超时,仅作兜底 -
SetDialer(&resty.Dialer{KeepAlive: 30 * time.Second})配合SetConnectionTimeout(2 * time.Second)控制建连阶段 -
SetReadTimeout(3 * time.Second)和SetWriteTimeout(3 * time.Second)分别管读响应和发请求体 - 对支付类等关键接口,建议连接超时 ≤1s,读超时 ≤2s;对非关键查询(如天气、汇率),可适当放宽
对接模块必须可配置、可开关、可降级
线上出问题时,没人会给你时间改代码。如果第三方服务挂了,你的接口不能跟着一起 503,得能快速切到缓存、默认值或熔断返回。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有第三方地址、Token、超时参数都从配置中心或环境变量读取,禁止硬编码
- 用
goframe的g.Cfg().GetString("thirdparty.payment.url")这类方式加载,便于灰度或动态更新 - 加一层简单开关,比如配置项
thirdparty.payment.enabled = false,true 时走真实请求,false 时直接返回模拟数据或错误 - 对非核心链路(如用户行为上报),考虑用
go-resty的ForceContentType("application/json")+ 空响应体快速 fail-fast,别让它拖慢主流程
真正难的不是调通一个接口,而是让这个模块在流量突增、依赖抖动、配置变更时依然稳得住。配置可变、错误可溯、超时可控、开关可切——这四点漏掉任何一项,都会在半夜收到告警。


















