调研探索
ASP.NET Core API 版本化:从第一天起用…
在 ASP.NET Core 中为 API 添加版本化、演进破坏性变更、弃用旧版本并集成 OpenAPI 时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
ASP.NET Core API 版本化通用
解决思路
- 从第一天就做版本化:即使只有 v1,也要在 URL 中带上版本号,后期再补版本化会很痛苦。
- 默认使用 URL 段版本化:`/api/v1/orders` 最易发现且对缓存友好。
- 绝不破坏已有版本:破坏性变更时新增一个版本,并为旧版本设定弃用时间线。
- 对 API 整体版本化,而不是对单个端点版本化:同一版本组内所有端点共享相同版本号。
- 使用 Asp.Versioning 进行配置:在 `Program.cs` 中调用 `builder.Services.AddApiVersioning`,设置 `DefaultApiVersion` 为 `new ApiVersion(1, 0)`、`AssumeDefaultVersionWhenUnspecified = true`、`ReportApiVersions = true`、`ApiVersionReader = new UrlSegmentApiVersionReader()`,并链式调用 `AddApiExplorer` 设置 `GroupNameFormat = "'v'VVV"` 与 `SubstituteApiVersionInUrl = true`。
- URL 段版本化(推荐):用 `app.NewApiVersionSet().HasApiVersion(new ApiVersion(1, 0)).Build()` 创建版本集,再用 `app.MapGroup("/api/v{version:apiVersion}/orders").WithApiVersionSet(v1).WithTags("Orders").MapOrderEndpointsV1()` 映射各版本端点组。
- Header 版本化(替代方案):设置 `options.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version")`,客户端发送 `X-Api-Version: 2.0`。
- 弃用某个版本:在版本集中用 `HasDeprecatedApiVersion(new ApiVersion(1, 0))` 标记旧版本,同时用 `HasApiVersion(new ApiVersion(2, 0))` 声明新版本;响应头会包含 `api-deprecated-versions: 1.0`。
- 按版本拆分端点组:为每个版本建立独立的静态类(如 `OrderEndpointsV1`、`OrderEndpointsV2`),各自实现 `MapOrderEndpointsVx(this RouteGroupBuilder group)` 方法,在方法内用 `group.MapGet`、`group.MapPost` 注册端点,并返回对应的 V1/V2 响应结构(如 `result.Value.ToV1()` 或 `result.Value.ToV2()`)。
- 不要对单个端点做版本化:避免同一组内出现 `/api/v1/orders` 与 `/api/v2/orders/{id}` 混用;应改为整组映射 `app.MapGroup("/api/v1/orders").MapOrderEndpointsV1()` 与 `app.MapGroup("/api/v2/orders").MapOrderEndpointsV2()`。
- 不要把查询字符串版本化作为默认方案:避免 `GET /api/orders?api-version=2.0`,应使用 `GET /api/v2/orders`,因为 URL 中的版本更易发现且可缓存。
- 按场景选择策略:新公开 API 从第一天起用 URL 段版本化;服务间内部 API 用 Header 版本化(URL 更干净);破坏性响应结构变更时新增版本;仅添加新的可选字段时保持同一版本(向后兼容);弃用版本时标记 deprecated、设定 sunset 日期并记录迁移路径。
适用边界 · 注意事项
- 仅添加新的可选字段、保持向后兼容时,不需要新增版本。
- 内部服务间 API 若更看重 URL 简洁,可不用 URL 段版本化而改用 Header 版本化。
- 不要把查询字符串版本化作为 REST API 的默认方案,因为它不易发现且对缓存不友好。