ASP.NET Core API版本控制
场景:
任何不断发展变化的API都需要API版本控制策略。你的API版本可以适应根据API使用者的期望而切换不同版本变得有所不同。我通常建议将以下API版本控制策略作为整体API管理系统的一部分。
1.如果你的API处于早期测试版本中,为了获得消费者的反馈,请建立您的API可能会发生变化的正确期望。在此阶段内,你会保留这个版本一段时间,因为你的API设计可能还会更改。作为消费者,API是不稳定的,因此他们应该预期到可能会发生的变化。
2.一旦发布,你的API应被视为契约,如果没有新版本,则不能被替换。
3.不间断的更改会导致次要版本出现问题,客户端会自动迁移到最新版本,不会出现任何负面副作用。
4.突破性的变化意味着客户必须迁移到此新版本,因为它包含一个或多个重大更改。你必须与API使用者建立适当的时间表并定期沟通,以确保他们能方便地迁移到新版本。但在某些情况下,这可能无法马上实现,所以你的团队将会被要求暂时性支持以前的API版本。
实现API版本控制的方法
Install-Package Microsoft.AspNetCore.Mvc.Versioning
在 Startup
的 ConfigureServices
中增加一下配置。然后在Configure方法添加app.UseApiVersioning();
services.AddApiVersioning(o => { //在请求响应标头(Header)中返回所有的版本信息(默认为api-supported-versions:1.0,2.0,3.0),可以在下面ApiVersionReader中自定义替代参数名称 o.ReportApiVersions = true; //此选项将用于不提供版本的请求。默认情况下, 假定的 API 版本为1.0 o.AssumeDefaultVersionWhenUnspecified = true; //缺省api版本号,支持时间或数字版本号 o.DefaultApiVersion = new ApiVersion(1, 0); //支持MediaType、Header、QueryString 设置版本号;缺省为QueryString、UrlSegment设置版本号 o.ApiVersionReader = ApiVersionReader.Combine( new MediaTypeApiVersionReader("api-version"), new HeaderApiVersionReader("api-version"),
new QueryStringApiVersionReader("api-version"), new UrlSegmentApiVersionReader()); });
其他参数:
o.ApiVersionSelector可以设置四种值来确定选择版本的策略
DefaultApiVersionSelector如果请求中没有指定,则选择默认版本
CurrentImplementationApiVersionSelector如果请求中没有指定,则选择最新的 api 版本
LowestImplementedApiVersionSelector如果请求中没有指定,则选择最低的 api 版本
ConstantApiVersionSelector不管请求是否指定, 一直选择在构造函数中传递的常量 api 版本
o.ErrorResponses设置版本匹配错误时返回的响应信息
o.RegisterMiddleware默认为true,可以省略在Configure方法添加app.UseApiVersioning();的代码
如果控制器不应用[ApiController]的话,需要设置o.UseApiBehavior = false;才能正常工作
(1)通过QueryString进行版本控制
分别在两个不同的Controller
中添加一个获取版本信息的接口
namespace version.Controllers.v1 { [ApiVersion("1.0")] [ApiController] [Route("api/[controller]")] public class ValuesController : Controller { [HttpGet("version")] public string Version() => (HttpContext.GetRequestedApiVersion().ToString()); } } namespace version.Controllers.v2 { [ApiVersion("2.0")] [ApiController] [Route("api/[controller]")] public class ValuesController : Controller { [HttpGet("version")] public string Version() => (HttpContext.GetRequestedApiVersion().ToString()); } }
HttpContext.GetRequestedApiVersion().ToString()
是用于获取请求接口的版本信息。
通过URL Path进行版本控制
一般在Api开发中不会去QueryString的方式去进行版本控制,而是使用URL路径段的方式来控制版本。
修改两个Controller
中的代码如下。
namespace version.Controllers.v1 { [ApiVersion("1.0")] [ApiController] [Route("api/v{version:ApiVersion}/[controller]")] public class ValuesController : Controller { [HttpGet("version")] public string Version() => (HttpContext.GetRequestedApiVersion().ToString()); } } namespace version.Controllers.v2 { [ApiVersion("2.0")] [ApiController] [Route("api/v{version:ApiVersion}/[controller]")] public class ValuesController : Controller { [HttpGet("version")] public string Version() => (HttpContext.GetRequestedApiVersion().ToString()); } }
不能像QueryString一样调用默认的Api版本,因为URL Path的方式不允许隐式匹配设置的默认Api版本。所以必须申明所有的Api版本。且在请求Api同时必须带上Api版本号。
[Route("api/v{version:ApiVersion}/[controller]")]中的ApiVersion可以通过o.RouteConstraintName = "ApiName";自定义
通过Media Type进行版本控制
我们还可以使用content-type
来实现版本的控制
分别修改两个Controller
namespace version.Controllers.v1
{
[ApiVersion("1.0")]
[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet("version")]
public string Version() => (HttpContext.GetRequestedApiVersion().ToString());
}
}
namespace version.Controllers.v2
{
[ApiVersion("2.0",Deprecated = true)]
[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet("version")]
public string Version() => (HttpContext.GetRequestedApiVersion().ToString());
}
}
访问时添加content-type:application/json;v=2.0
Deprecated = true表示API已过时
如果应用[ApiVersionNeutral]则表示此Controller或Action不需要版本控制
MapToApiVersion 用法举例
[Route("api/v{version:apiVersion}/[controller]")] [ApiVersion("1")] [ApiVersion("3")] public class ValuesController : Controller { [HttpGet] public IEnumerable<string> Get1() { return new string[] {}; } [HttpGet, MapToApiVersion("2"), MapToApiVersion("4")] public IEnumerable<string> Get2() { return new string[] {}; } [HttpGet, MapToApiVersion("5")] public IEnumerable<string> Get3() { return new string[] {}; } }
Get1支持的版本是:1、3;
Get2支持的版本是:2、4;
Get3支持的版本是:5。