进阶 www.iris-go.com 2026-10-20 02:39:14 · 19 阅读

第61章 API 版本控制

API 版本控制(Versioning) versioning 子包为你的 API 提供 semver(语义化版本)支持。它实现了所有最佳实践约定,包括 api-guidelines 文档中的建议。版本号从请求头 "Accept" 和/或 "Accept-Version" 中获取。如果版本匹配成功,服务器会通过自定义响应头 "X-Api-Version" 返回标准化后的版本号。如果没有匹配到版本(缺少版本头或版本未实现),服务器默认返回 501 状态码和纯文本 "version not found"。如果某个资源版本已被服务器标记为弃用,客户端会收到自定义响应头 "X-Api-Warn"、"X-Api-Deprecation-Date" 和 "X-Api-Deprecation-Info",同时请求仍会按预期正常处理。 简介 内部实现上,版本校验使用了无正则、高性能的第三方包 github.com/blang/semver/v4。 合法的版本范围包括:"<1.0.0"、"<="1.0.0"">1.0.0"">=1.0.0""1.0.0"、"=1.0.0"、""1.0.0"(等于)"!1.0.0"、""(不等于) 一个范围(Range)可以由多个子范围用空格分隔组成: 子范围之间可用逻辑 AND 连接: ">1.0.0 <2.0.0" 匹配两个范围之间的版本,如 "1.1.1" 和 "1.8.7",但不匹配 "1.0.0" 或 "2.0.0" ">1.0.0 <3.0.0 !2.0.3-beta.2" 匹配 1.0.0 到 3.0.0 之间的所有版本,但排除 2.0.3-beta.2 子范围也可以用逻辑 OR 连接: "<2.0.0 || >=3.0.0" 匹配 "1.x.x" 和 "3.x.x",但不匹配 "2.x.x" AND 的优先级高于 OR,且不支持使用括号。 AND 和 OR 可以组合使用: >1.0.0 <2.0.0 || >3.0.0 !4.2.1 匹配 1.2.3、1.9.9、3.1.1,但不匹配 4.2.1 和 2.1.1。 快速开始 导入 versioning 包。 go import ( // [...] "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/versioning" ) 1 2 3 4 5 6 通过 `versioning.NewGroup(version string) *versioning.Group` 函数,你可以创建一个路由组,用于根据客户端请求的版本注册应用路由。`versioning.Group` 实现了 `iris.Party` 接口。 示例代码: ```golang package main import ( "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/versioning" ) func main() { app := iris.New() app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context) { ctx.WriteString(`Root not found handler. This will be applied everywhere except the /api/* requests.`) }) api := app.Party("/api") // 可选:设置版本别名(字面量字符串)。 // 这里使用 `UseRouter` 而非 `Use`, // 以便按版本处理 HTTP 错误,但具体取决于你的需求。 api.UseRouter(versioning.Aliases(versioning.AliasMap{ // 如果客户端未提供版本,默认设为 "1.0.0"。 versioning.Empty: "1.0.0", // 如果客户端提供 "latest" 版本, // 将比较用的版本设为 "3.0.0"。 "latest": "3.0.0", })) // |----------------| // | 有趣的部分开始 | // |----------------| // 基于版本约束创建一个新的 Group,它兼容 Party。 v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0") // 可选:按版本设置自定义的模板引擎和路径。 v1.RegisterView(iris.HTML("./v1", ".html")) // 可选:按版本设置自定义的错误处理程序。 // 注意:如果这样做,你还必须 // 为其余的 parties 注册错误处理程序。 v1.OnErrorCode(iris.StatusNotFound, testError("v1")) // 按版本注册资源。 v1.Get("/", testHandler("v1")) v1.Get("/render", testView) // 为了示例完整性,对版本 2 和版本 3 做相同操作。 v2 := versioning.NewGroup(api, ">=2.0.0 <3.0.0") v2.RegisterView(iris.HTML("./v2", ".html")) v2.OnErrorCode(iris.StatusNotFound, testError("v2")) v2.Get("/", testHandler("v2")) v2.Get("/render", testView) v3 := versioning.NewGroup(api, ">=3.0.0 <4.0.0") v3.RegisterView(iris.HTML("./v3", ".html")) v3.OnErrorCode(iris.StatusNotFound, testError("v3")) v3.Get("/", testHandler("v3")) v3.Get("/render", testView) app.Listen(":8080") } func testHandler(v string) iris.Handler { return func(ctx iris.Context) { ctx.JSON(iris.Map{ "version": v, "message": "Hello, world!", }) } } func testError(v string) iris.Handler { return func(ctx iris.Context) { ctx.Writef("not found: %s", v) } } func testView(ctx iris.Context) { ctx.View("index.html") } ```
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
版本别名​ 可选,设置版本别名(字面字符串)。goapi.UseRouter(versioning.Aliases(versioning.AliasMap{ // 如果客户端未提供版本,默认为 "1.0.0"。 versioning.Empty: "1.0.0", // 如果客户端提供 "latest" 版本, // 则将与 "3.0.0" 进行比较。 "latest": "3.0.0", }))1
2
3
4
5
6
7
我们使用 UseRouter 而不是 Use 来按版本处理 HTTP 错误,但这由您决定。获取当前版本​ 版本通过 versioning.GetVersion 函数提取。即使不使用版本控制功能,也可以在任何地方使用它。默认情况下,GetVersion 会尝试从以下位置读取:Accept 请求头,例如 Accept: "application/json; version=1.0.0"Accept-Version 请求头,例如 Accept-Version: "1.0.0"可以通过设置基于请求上下文的版本来自定义:goapi.Use(func(ctx *context.Context) { if version := ctx.URLParam("version"); version != "" { versioning.SetVersion(ctx, version) } ctx.Next() })1
2
3
4
5
6
7
或者使用 FromQuery(version, default) 辅助函数:goapi.Use(versioning.FromQuery("version", "1.0.0"))1
弃用​ 要标记 API 版本为已弃用,请使用 Deprecated 方法。gov1.Deprecated(versioning.DefaultDeprecationOptions)1
这将使路由处理器向客户端发送一些额外的请求头。"X-API-Warn": options.WarnMessage"X-API-Deprecation-Date": context.FormatTime(ctx, options.DeprecationDate))"X-API-Deprecation-Info": options.DeprecationInfo

评论 (0)