应严格分离api版本与业务逻辑:路由层分发(如subrouter/mount)、结构体物理隔离(v1/v2独立定义)、依赖通过适配器封装、清理时同步更新go.sum并移除context.value传递版本。

直接改 go.mod 或在 handler 里加 if version == "v2" 是最危险的起点——它会让版本逻辑和业务逻辑缠死,后续任何一次小改动都可能同时破坏 v1 和 v2 的稳定性。
先停掉所有“动态路由”硬编码
旧项目常见做法是:一个 GET /users handler 里用 query 参数或 header 解析版本,再分支调用不同逻辑。这导致测试难覆盖、中间件无法按版本启用、监控指标混在一起。
- 立刻删除所有类似
r.GET("/users", func(c *gin.Context) { if c.Query("version") == "v2" { ... } })的写法 - 禁止在 handler 函数体内做版本判断;版本分发必须由路由层完成
- 如果用了
gorilla/mux,确保每个版本都走subr := r.PathPrefix("/v1").Subrouter(),而不是靠strings.HasPrefix手动切 - 如果用了
chi,必须用r.Mount("/v2", v2Router),别用r.Group("/v2")—— 后者不隔离中间件,v1 的日志中间件会漏进 v2
结构体必须物理隔离,哪怕字段完全一样
共用 User struct 是遗留系统最隐蔽的坑:v1 客户端收到 v2 新增的 Nickname 字段,前端 JSON.parse 就可能失败;v2 用 omitempty 而 v1 不用,会导致空字符串被忽略或意外透出。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 为每个版本建独立目录:
api/v1/user.go和api/v2/user.go - 定义
UserV1和UserV2,即使当前字段名、类型、tag 全部一致,也绝不复用 - 数据库 model(如
db.User)保持稳定,只做存储;API 层用显式赋值或mapstructure.Decode做转换,不靠反射自动映射 - Swagger 注释(如
@Success 200 {object} api.UserV1)必须绑定到对应版本的 handler 文件,不能跨版本引用
用适配器封装旧版调用,而非直接替换包
升级 jwt-go v3 → v4 或 golangci-lint v1 → v2 这类依赖大版本时,别急着删旧 import。很多 panic 其实来自旧版错误处理逻辑被新 API 绕过,比如 jwt.Parse 在 v4 中移除了 Keyfunc 的 error 返回,但旧代码里写了 if err != nil && !errors.Is(err, jwt.ErrTokenExpired),现在这个分支永远不进。
- 新建
pkg/jwtadapter,定义统一接口:type Verifier interface { Verify(tokenString string) (Claims, error) } - v3 实现里调
github.com/dgrijalva/jwt-go,v4 实现里调github.com/golang-jwt/jwt/v4并做token.Claims.(jwt.MapClaims)显式转换 - 业务 handler 只依赖
Verifier,注入时按版本切换实现;升级过程可灰度控制(如通过X-Api-Version: v4header 控制部分请求走新 adapter) - 适配器里加日志:
log.Printf("jwt: v4 adapter used, token id=%s, valid=%t", token.Header["jti"], token.Valid),方便确认流量是否真实切换
清理阶段最容易漏掉 go.sum 和 context.Value
第三阶段“清理旧包”不是删掉 import 就完事。残留的旧版本哈希会让 CI 在 go mod verify 阶段失败;而把版本号从 context.Context 里取出来再传给 service,等于又把路由层的版本语义拖回了业务层。
-
go.mod删掉旧依赖后,手动打开go.sum,搜索并删除所有含旧路径(如github.com/dgrijalva/jwt-go)的行,再跑go mod tidy - 禁止在 middleware 里写
ctx = context.WithValue(ctx, "version", version);版本信息应仅用于路由分发,service 层不该感知 - 确认监控中旧版本 endpoint 的 QPS 归零(不只是 200,还要看 4xx/5xx),再删
handlers/v1/目录和api/v1/ - 最后检查所有
go test ./...是否仍通过——尤其注意那些 mock 了旧版 jwt 包的测试,它们很可能还在用已删除的类型
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










