api - REST API版本控制

标签 api rest

在阅读了很多有关REST版本控制的资料之后,我想对调用而不是API进行版本控制。例如:

http://api.mydomain.com/callfoo/v2.0/param1/param2/param3
http://api.mydomain.com/verifyfoo/v1.0/param1/param2


而不是先有

http://api.mydomain.com/v1.0/callfoo/param1/param2
http://api.mydomain.com/v1.0/verifyfoo/param1/param2


然后去

http://api.mydomain.com/v2.0/callfoo/param1/param2/param3
http://api.mydomain.com/v2.0/verifyfoo/param1/param2


我看到的优势是:


更改呼叫后,我不必重写整个客户端-只需重写受更改呼叫影响的部分即可。
客户端中运行良好的部分可以按原样继续(我们投入了大量测试时间,以确保客户端和服务器端均稳定。)
我可以将永久性或非永久性重定向用于已更改的呼叫。
向后兼容将是一件轻而易举的事,因为我可以保留旧版本的呼叫。


我在想什么吗?请指教。

最佳答案

需要HTTP标头。

Version: 1

Version标头临时注册在RFC 4229中,出于某些合理的原因,请避免使用X前缀或特定用途的URI。 yfeldblum在https://stackoverflow.com/a/2028664处提出了一个更典型的标头:

X-API-Version: 1

在任何一种情况下,如果标头丢失或与服务器提供的内容不匹配,请发送412 Precondition Failed响应代码以及失败原因。这就要求客户端每次都指定其支持的版本,但是必须在客户端和服务器之间强制执行一致的响应。 (可选地支持?version=查询参数将为客户端提供更多的灵活性。)

这种方法简单,易于实施且符合标准。

备择方案

我知道一些非常聪明,好主意的人建议使用URL版本控制和内容协商。两者在某些情况下以及通常建议的形式都存在重大问题。

网址版本控制

如果您控制所有服务器和客户端,则可以使用端点/服务URL版本控制。否则,您将需要处理较新的客户端,这些客户端将退回到较旧的服务器上,最终将使用自定义HTTP标头完成此操作,因为部署在控件外部的异构服务器上的服务器软件的系统管理员可以做各种事情来搞砸如果您使用“ 302临时移动”之类的字词,那么您认为很容易解析的网址。

内容协商

如果您非常关注遵循HTTP标准,但又想忽略HTTP / 1.1标准文档的实际内容,则通过Accept标头进行内容协商是可行的。您倾向于看到的建议的MIME类型是application/vnd.example.v1+json形式。有几个问题:


当然,在某些情况下,供应商扩展实际上是适当的,但是客户端和服务器之间的稍微不同的通信行为实际上并不适合新的“媒体类型”的定义。另外,RFC 2616 (HTTP/1.1)读到:“媒体类型值已向Internet分配号码授权机构进行了注册。RFC1590中概述了媒体类型注册过程。不鼓励使用未注册的媒体类型。”我不想为具有REST API的每个软件产品的每个版本看到单独的媒体类型。
任何子类型范围(例如application/*)都没有意义。对于将结构化数据返回给客户端以进行处理和格式化的REST API,接受*/*有什么好处?
Accept头需要花费一些精力才能正确解析。应该同时使用隐式和显式优先级,以最大程度地减少实际正确进行内容协商所需的往返时间。如果您担心正确实施此标准,那么正确一点很重要。
RFC 2616 (HTTP/1.1)描述了不包含Accept标头的任何客户端的行为:“如果不存在Accept标头字段,则假定客户端接受所有媒体类型。”因此,对于没有编写自己的客户端的客户(您控制最少的地方),最正确的做法是使用服务器知道的最新,最容易破坏的旧版本版本来响应请求关于。换句话说,您可能根本没有实现版本控制,而那些客户端仍将以完全相同的方式破坏。


编辑,2014年:

我已经阅读了很多其他答案以及每个人的体贴评论;我希望我可以通过几年的反馈来改善这一点:


Don't use an 'X-' prefix。我认为Accept-Version在2014年可能更有意义,并且对注释中提出的重用Version的语义存在一些合理的担忧。确定的标头(例如Content-Version)和URI的相对不透明性有一定的重叠,因此,我尝试小心将两者与内容协商的变体(Version标头实际上是这样)相混淆。 URL https://example.com/api/212315c2-668d-11e4-80c7-20c9d048772b的第三个“版本”与“第二个”完全不同,无论它包含数据还是文档。
关于我上面所说的有关URL版本控制的内容(例如,像https://example.com/v1/users这样的端点),相反的说法可能更真实:如果您控制所有服务器和客户端,则可能需要URL / URI版本控制。对于可以发布单个服务URL的大型服务,我将为每个版本like most do使用不同的终结点。我的特殊观点受到这样一个事实的严重影响,即上述实现通常由许多不同的组织部署在许多不同的服务器上,也许最重要的是部署在我无法控制的服务器上。我一直想要一个规范的服务URL,如果网站仍在运行API的v3版本,我绝对不希望https://example.com/v4/的请求返回其Web服务器的404 Not Found页面(甚至更糟, 200 OK,将他们的首页作为500k HTML(通过蜂窝数据返回到iPhone应用程序)。)
如果您想要非常简单的/ client /实现(以及更广泛的采用),那么很难争辩说,对于客户端作者而言,在HTTP请求中要求自定义标头就像GET-设置普通URL一样简单。 (尽管身份验证通常需要在令牌头中传递您的令牌或凭证,但是,将VersionAccept-Version用作秘密握手以及实际的秘密握手非常合适。)
使用Accept标头进行的内容协商非常适合于为相同的内容获取不同的MIME类型(例如XML与JSON与Adobe PDF),但未针对这些版本定义(Dublin Core 1.1与JSONP与PDF)。 /一种)。如果您要支持Accept标头,因为遵守行业标准很重要,那么您就不想让伪造的MIME类型干扰您可能需要在请求中使用的媒体类型协商。定制的API版本标头保证不会干扰经常使用的,经常被引用的Accept,而将它们混用成相同的用法只会使服务器和客户端感到困惑。就是说,出于多种原因,按2013年的RFC6906将期望的内容命名为命名的配置文件优于单独的标头。这非常聪明,我认为人们应该认真考虑这种方法。
为每个请求添加标头是在无状态协议中工作的一个特殊缺点。
恶意代理服务器几乎可以采取任何措施破坏HTTP请求和响应。 They shouldn't,尽管在​​这种情况下我不谈论Cache-ControlVary标头,但所有服务创建者都应仔细考虑如何在许多不同的环境中使用其内容。

关于api - REST API版本控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57852040/

相关文章:

python - Python 中的 REST API 与 FastAPI 和 pydantic : read-only property in model

java - 在 Rest-assured 中使用 Json 文件作为负载

javascript - 使用 Google Maps API 显示标记

api - 多个发送者,1 个次要接收者?

ios - 使用 Swift 解析 tableview 中的 Json

python - 使用python从netsuite获取和推送数据

html - HTML 的 Restful 设计模式

Trello API : determine when a card changed lists?

java - Android _ 如何获取标记在谷歌地图 v2 上的位置并将其与 Latlng 数组匹配

java - 通过 HttpURLConnection 的 JSON POST 数据