c# - ASP.NET API 版本范围
问题描述
我们的产品是一个client/server
应用程序,它在现场有多个版本的客户端,但只有一个运行最新版本的服务器来服务所有API
呼叫。我们有/将有数百个API
端点,我正在尝试如何最好地处理版本控制。我想做的是能够避免应用attributes
到每一个方法的繁重任务,或者每次我们进行微小的更改时复制整个控制器。
我可能会误解大多数关于此的文件/实践,但似乎每次你碰到你的时候API
你都必须经历并完成所有这些工作,这似乎充其量是低效的。
相反,我想做的是使用编写时attribute
的版本对每个端点应用一个,然后客户端找到等于或小于客户端版本的最接近的版本。
例如,如果端点被写入,[ApiVersion("1.0")]
那么这就是它获得的属性。如果我们必须修改它,我会复制方法,重命名它,应用 aRoutePrefix
attribute
以便正确命中并应用attribute
我们整体版本的新方法API
(在这个例子中,我放了1.5
)。
这是一个简单的例子:
[HttpGet]
[ApiVersion("1.0")]
[Route("GetHeartBeat")]
public bool GetHeartBeat()
{
return true;
}
[HttpGet]
[ApiVersion("1.5")]
[Route("GetHeartBeat")]
public bool GetHeartBeat2()
{
return false;
}
当我使用 url 版本控制时,这没有问题:
/api/v1.0/GetHeartBeat
或者/api/v1.5/GetHeartBeat
但/api/v1.3/GetHeartBeat
没有,因为那个版本不存在..
我想要发生的是,如果我有一个正在运行的客户端1.3
,那么它将找到等于或小于最新版本的最接近的版本。所以/api/v1.3/GetHeartBeat
会收到,因为1.3
不存在,然后它会查看最接近/早期的版本,在这种情况下是1.0
.
我可以写一堆路由逻辑来完成这个,但我觉得必须有一个开箱即用的解决方案,因为我不能成为第一个尝试这个的人。有没有一个nuget
包可以做到这一点?
解决方案
你真的问了两个问题。如何在服务器端映射事物是一个实现细节,有很多选择。属性不是应用 API 版本控制元数据的硬性要求。您可以使用约定,包括您自己的约定。API 版本必须是离散的。那是设计使然。API 版本更像是一种媒体类型。您不能随意添加媒体类型或 API 版本,并且必须期望客户端能够理解它。
由于您拥有双方,因此您有一些很好的途径可以让事情按照您想要的方式进行。服务器永远不应该假设客户端想要什么,客户端应该总是明确地询问服务器它想要什么。实现目标的最简单方法是协商API 版本。好,很好。如何?
我怀疑今天没有很多人这样做,但 API 版本控制在很早的时候就包含了必要的机制来实现这一点。有很多用例,但最常见的是工具(例如:客户端代码生成)和客户端版本协商。第一步是启用报告 API 版本:
services.AddApiVersioning(options => options.ReportApiVersions = true);
您还可以应用于
[ReportApiVersions]
特定的控制器操作
这将允许通过api-supported-versions
和api-deprecated-versions
HTTP 标头报告可用的 API 版本。请记住,弃用并不意味着它不存在,它只是意味着它会在某个时候消失;你控制政策。您的客户可以使用此信息来记录有关过时版本的警告,或者它会影响您的客户选择合适版本的决定。
您面临的部分挑战是按 URL 段进行版本控制。是的,它非常流行,但它违反了统一接口约束。v1.api.com
是一个端点。v1.0/GetHeartBeat
并且v1.5/GetHeartBeat
是标识符。这两个识别的资源几乎可以肯定不是不同的资源,而是具有不同的表示。为什么这很重要?更改每个版本的标识符(例如 URL)会导致客户端移动目标。其他所有版本控制方法都将使用 always use GetHeartBeat
。我敢肯定,您做出改变的路太远了,但这会导致解决方案。
您使用哪个控制器实现并不重要,但您基本上需要一个执行以下操作的操作:
[ApiController]
[Route("api/[controller]")]
public class GetHeartBeatController : ControllerBase
{
[ReportApiVersions] // ← instead of ApiVersioningOptions.ReportApiVersions = true
[ApiVersionNeutral] // ← allow any and all versions, including none at all
[HttpOptions]
public IActionResult Options()
{
// Allow is required by spec; you may need addition information
Response.Headers.Add("Allow", new StringValues(new[]{"GET", "OPTIONS"}));
Response.GetTypedHeaders().CacheControl = new()
{
MaxAge = TimeSpan.FromDays(1d),
};
return Ok();
}
}
现在,如果您的客户发送:
OPTIONS api/getheartbeat HTTP/2
Host: localhost
你会得到类似的东西:
HTTP/2 200 OK
Cache-Control: max-age=86400
Api-Supported-Versions: 1.0, 1.5
如果您的客户端正在运行1.3
,它现在具有1.0
从列表中选择最合适的 API 版本所需的知识。标Cache-Control
头可以用作服务器告诉客户端它可以缓存结果多长时间的一种方式(但它不是必须的)。我认为 API 版本的更改频率不会超过每天一次,因此这似乎是一种合理的方法。
你没有提到你有什么类型的客户。如果它是基于浏览器的客户端,您可能需要对此设置进行一些额外的工作,以使其与 CORS 配合使用(如果需要)。或者,您可以使用该HEAD
方法获得相同的结果。我认为这OPTIONS
更合适,但如果您遇到任何复杂情况,您可能会发现让它与 CORS 一起玩的工作不值得。
推荐阅读
- wms - WMS getcapabilities 仅获取特定层的 xml
- reactjs - 如何在 axios 中使用基于令牌的身份验证并做出反应
- php - 如何在laravel中查询对象数组
- javascript - 当反转并加入的数组对象的控制台日志返回一个字母时
- sql-server - SQL Server 为什么函数内部的 geography::Point 是不确定的?
- mysql - 如何在 Docker MySQL 映像上允许外部连接
- python - 存储聚类结果
- react-native - 反应原生,scrollView 正在修剪空的“视图”组件(也有背景颜色)
- sql-server - 通过 JDBC 使用 Google Apps 脚本的 SQL Server
- apache-nifi - 如何在 Cloudflare 后面设置 Apache Nifi?