我们在开发 webapi 项目时如果遇到 api 接口需要同时支持多个版本的时候 , 比如接口修改了入参之后但是又希望支持老版本的前端(这里的前端可能是网页 , 可能是App,小程序 等等)进行调用 , 这种情况常见于 app , 毕竟网页前端我们可以主动控制发布 , 只要统一发布后所有人的浏览器下一次访问网页时都会重新加载到最新版的代码 , 但是像 app 则无法保证用户一定会第一时间升级更新最新版的app , 所以往往需要 api接口能够同时保持多个版本的逻辑 , 同支持新老版本的调用端app进行调用 。
针对上面的描述举一个例子:
比如一个创建用户的接口 , api/user/createuser
如果我们这个时候对该接口的入参和返回参数修改之后 , 但是又希望原本的 api/user/createuser 接口逻辑也可以正常运行 , 常见的做法有以下几种:
- 修改接口名称 , 将新的创建用户接口地址定义为 api/user/newcreateuser
- url传入版本标记 , 将新的创建用户接口地址定义为 api/user/createuser?api-version=2
- header传入版本标记 , 通过校验 header 中的 api-version 字段的值 , 用来区分调用不同版本的api
截至本文撰写时间 , 最新的 .net 版本为 .net6 , 本文中的所有示例也是基于 .net 6 来构建的 。
首先创建一个 asp.net webapi 项目 , 本文使用 vs2022 直接创建 asp.net webapi 项目
项目创建好之后安装如下几个nuget包:
Swashbuckle.AspNetCore
Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
注册 api 版本控制服务
#region 注册 api 版本控制builder.Services.AddApiVersioning(options =>{//通过Header向客户端通报支持的版本options.ReportApiVersions = true;//允许不加版本标记直接调用接口options.AssumeDefaultVersionWhenUnspecified = true;//接口默认版本//options.DefaultApiVersion = new ApiVersion(1, 0);//如果未加版本标记默认以当前最高版本进行处理options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);//配置为从 Header 传入 api-versionoptions.ApiVersionReader = new HeaderApiVersionReader("api-version");//配置为从 Query 传入 api-version//options.ApiVersionReader = new QueryStringApiVersionReader("api-version");});builder.Services.AddVersionedApiExplorer(options =>{options.GroupNameFormat = "'v'VVV";options.SubstituteApiVersionInUrl = true;});#endregion
这里我们可以选择 api-version 版本标记的传入方式是从 url query 传递还是从 http header 传递 。移除项目默认的 swagger 配置
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}
采用如下 swagger 配置#region 注册 Swaggerbuilder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerConfigureOptions>();builder.Services.AddSwaggerGen(options =>{options.OperationFilter<SwaggerOperationFilter>();options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml"), true);});#endregion
其中用到了两个自定义的类 SwaggerConfigureOptions 和 SwaggerOperationFilter , SwaggerConfigureOptions 是一个自定义的 Swagger 配置方法 , 主要用于根据 api 控制器上的描述用来循环添加不同版本的 SwaggerDoc;
SwaggerOperationFilter 是一个自定义过滤器主要实现SwaggerUI 的版本参数 api-version 必填验证和标记过期的 api 的功能 , 具体内容如下
SwaggerConfigureOptions .cs
/// <summary>/// 配置swagger生成选项 。/// </summary>public class SwaggerConfigureOptions : IConfigureOptions<SwaggerGenOptions>{readonly IApiVersionDescriptionProvider provider;public SwaggerConfigureOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;public void Configure(SwaggerGenOptions options){foreach (var description in provider.ApiVersionDescriptions){options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));var modelPrefix = Assembly.GetEntryAssembly()?.GetName().Name + ".Models.";var versionPrefix = description.GroupName + ".";options.SchemaGeneratorOptions = new SchemaGeneratorOptions { SchemaIdSelector = type => (type.ToString()[(type.ToString().IndexOf("Models.") + 7)..]).Replace(modelPrefix, "").Replace(versionPrefix, "").Replace("`1", "").Replace("+", ".") };}}static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description){var info = new OpenApiInfo(){Title = Assembly.GetEntryAssembly()?.GetName().Name,Version = "v" + description.ApiVersion.ToString(),//Description = "",//Contact = new OpenApiContact() { Name = "", Email = "" }};if (description.IsDeprecated){info.Description += "此 Api " + info.Version + " 版本已弃用 , 请尽快升级新版";}return info;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 通过感染病毒实现群体免疫不科学-通过感染实现自身免疫
- 算法:正则表达式匹配
- Frp内网穿透之p2p实现远程桌面
- 防火墙配置,实现总部与分部IPsec vpn互联
- 两个方法都可以,OPPO手机实现屏幕共享和远程协助
- 微软|Win11新补丁如期而至:自家.NET 3.5又双叒叕崩了
- 修容|圆脸肉脸怎么实现快速变美,这3点很关键
- SpringBoot整合JWT实现登录认证
- 跳表在Java中的实现
- 关于特斯拉的预言,尼古拉特斯拉十大预言已实现6个-