推荐用工厂函数返回定制化 *http.Client 或封装请求函数,Token 作为参数传入或闭包捕获;必须在 http.NewRequest 后、client.Do() 前调用 req.Header.Set("Authorization", "Bearer "+token),注意空格和字符合法性;401 需业务层捕获并手动刷新重试。

如何用 http.Client 封装带 JWT 的请求逻辑
直接复用 http.Client,别每次手动塞 Authorization 头。核心是把 Token 注入到 http.Request 的 Header 中,且必须在调用 client.Do() 前完成。
推荐做法:写一个工厂函数,返回定制化的 *http.Client 或封装好的请求函数。避免全局变量存 Token —— 它可能过期或切换用户。
- Token 应作为参数传入,或从闭包捕获(如从 token store 接口获取)
- 不要在
http.Transport或http.RoundTripper层硬编码 Token —— 那会导致所有请求共用同一 Token,无法按需刷新 - 若 Token 来自外部(比如登录后返回),确保它已 Base64Url 解码校验过,否则
Bearer xxx会 401
http.NewRequest 时怎么安全加 Authorization 头
必须在 http.NewRequest 后、client.Do() 前调用 req.Header.Set()。顺序错了就白设。
常见错误:先调 client.Do(req) 再设 Header —— 此时请求已发出,Header 修改无效。
- 正确顺序:
req, _ := http.NewRequest(...); req.Header.Set("Authorization", "Bearer "+token); client.Do(req) - 注意空格:值必须是
"Bearer " + token,不是"Bearer" + token(少个空格 → 401) - Token 字符串不能含换行或控制字符,否则 HTTP 请求头解析失败,服务端可能直接拒收
如何避免 Token 过期导致的 401 不重试问题
自动附加 Token 不等于自动刷新 Token。HTTP 客户端本身不感知 Token 生命周期,401 就是 401,不会自动重发。
真正要做的,是在业务层捕获 401 并触发刷新流程,再重试原请求 —— 这部分必须你自己控制,没法靠封装函数“一键解决”。
- 不要在封装函数里直接
if resp.StatusCode == 401 { refresh(); retry }—— 这会让函数职责爆炸,且难以测试 - 建议把请求函数设计为可组合:先执行,再由上层判断状态码,决定是否调用
refreshToken()后重试 - 如果用
context.Context控制超时/取消,记得重试时新建req.WithContext(newCtx),否则可能沿用已 cancel 的 context
要不要用 http.RoundTripper 实现自动 Token 注入
可以,但只推荐在 Token 全局唯一、长期有效、且无需按请求动态变更时使用。绝大多数业务场景下,它反而增加复杂度和调试难度。
典型误用:在 RoundTrip 方法里读取某个全局 token 变量,结果并发请求间互相覆盖、或刷新时出现竞态。
- 如果你真要用,务必保证
RoundTripper实例是线程安全的,Token 获取逻辑需加锁或用atomic.Value - 更稳妥的做法是:每个请求显式传 Token,靠类型系统约束(例如定义
DoWithToken(client *http.Client, token string, req *http.Request)) - 第三方库如
go-jose或golang-jwt/jwt只负责签发/验证,不处理 HTTP 层注入 —— 别指望它们替你做 Header 设置

















