Answers:
我会说最好将它作为URI本身的一部分(选项1),因为v4标识的资源不同于v3。像您在第二个选项中那样的查询参数最适合用于传递与请求相关的其他(查询)信息,而不是资源。
不要版本化URL,因为...
假设您的资源返回了application / vnd.yourcompany.user + xml的某种变体,那么您需要做的就是为新的application / vnd.yourcompany.userV2 + xml媒体类型创建支持,并通过内容协商的魔力来实现v1和v2客户可以和平共处。
在RESTful接口中,与合同最接近的就是定义客户端与服务器之间交换的媒体类型。
客户端用于与服务器交互的URL应由嵌入在先前检索的表示形式中的服务器提供。客户端唯一需要知道的URL是接口的根URL。仅当您在客户端上构造url时,才将版本号添加到url中才有价值,而这并不是您想使用RESTful接口实现的。
如果您需要更改将破坏现有客户的媒体类型,那么请创建一个新的客户,不要理会您的网址!
对于当前那些读者来说,如果我使用application / xml和application / json作为媒体类型,这毫无意义。我们应该如何对这些版本进行版本控制?你不是。除非您使用代码下载来解析它们,否则这些媒体类型对于RESTful接口几乎是无用的,在这一点上,版本控制才是关键。
啊,我又戴上了我那脾气暴躁的旧帽子。
从ReST的角度来看,这根本没有关系。不是香肠
客户端收到它要遵循的URI,并将其视为不透明字符串。将任何内容放入其中,客户端都不知道版本标识符之类的内容。
客户知道它可以处理媒体类型,我建议您遵循Darrel的建议。我个人还认为,需要四次更改宁静的架构中使用的格式,这会带来巨大的警告信号,表明您在做严重错误的事情,并完全绕过了设计介质类型以提高变化弹性的需求。
但是,无论哪种方式,客户端都只能以其可以理解的格式处理文档,并遵循其中的链接。它应该知道链接关系(过渡)。因此,URI中的内容完全不相关。
我个人会投票支持http:// localhost / 3f3405d5-5984-4683-bf26-aca186d21c04
一个完全有效的标识符,它将防止任何其他客户端开发人员或其他人接触系统,以质疑是否应将v4放在URI的开头或结尾(并且我建议从服务器的角度来看,您不应有4个版本,但有4种媒体类型)。
您不应将版本放在URL中,而应将版本放在请求的“接受标头”中-在此线程上查看我的文章:
如果您开始在URL中粘贴版本,则最终会得到类似以下的愚蠢URL:http : //company.com/api/v3.0/customer/123/v2.0/orders/4321/
此外,还有许多其他问题在蔓延-请参阅我的博客:http : //thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html
关于REST API版本控制的这些(不太具体的)SO问题可能会有所帮助:
有4种不同的API版本控制方法:
将版本添加到URI路径:
http://example.com/api/v1/foo
http://example.com/api/v2/foo
当您进行重大更改时,必须增加版本,例如:v1,v2,v3 ...
您可以在代码中实现一个控制器,如下所示:
@RestController
public class FooVersioningController {
@GetMapping("v1/foo")
public FooV1 fooV1() {
return new FooV1("firstname lastname");
}
@GetMapping("v2/foo")
public FooV2 fooV2() {
return new FooV2(new Name("firstname", "lastname"));
}
请求参数版本控制:
http://example.com/api/v2/foo/param?version=1
http://example.com/api/v2/foo/param?version=2
版本参数可以是可选参数,也可以是必需参数,具体取决于您希望API的使用方式。
实现可以与此类似:
@GetMapping(value = "/foo/param", params = "version=1")
public FooV1 paramV1() {
return new FooV1("firstname lastname");
}
@GetMapping(value = "/foo/param", params = "version=2")
public FooV2 paramV2() {
return new FooV2(new Name("firstname", "lastname"));
}
传递自定义标头:
http://localhost:8080/foo/produces
带标题:
headers[Accept=application/vnd.company.app-v1+json]
要么:
headers[Accept=application/vnd.company.app-v2+json]
该方案的最大优点是语义:不会使URI与版本控制有关。
可能的实现:
@GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
public FooV1 producesV1() {
return new FooV1("firstname lastname");
}
@GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
public FooV2 producesV2() {
return new FooV2(new Name("firstname", "lastname"));
}
更改主机名或使用API网关:
本质上,您要将API从一个主机名移到了另一个。您甚至可以调用此方法为相同的资源构建一个新的API。
另外,您可以使用API网关执行此操作。
我想创建版本化的API,发现本文非常有用:
http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http
关于“我希望对API进行版本控制”有一小节。我发现它简单易懂。关键是要使用标题中的Accept字段来传递版本信息。
如果使用URI进行版本控制,则版本号应位于API根目录的URI中,因此每个资源标识符都可以包含该版本号。
从技术上讲,REST API不会因URL更改(统一接口约束的结果)而中断。仅当相关语义(例如,特定于API的RDF vocab)以非向后兼容方式(罕见)更改时,它才会中断。当前,许多ppl不使用链接进行导航(HATEOAS约束)和vocab注释其REST响应(自描述消息约束),这就是其客户端中断的原因。
自定义MIME类型和MIME类型版本控制无济于事,因为将相关的元数据和表示的结构放入短字符串中不起作用。Ofc。元数据和结构会经常更改,因此版本号也是如此。
因此,回答您的问题的最佳方法是用词汇表(Hydra,链接数据)注释您的请求和响应,并忘记版本控制或仅通过不向后兼容的词汇表更改来使用它(例如,如果您要用另一个替代词汇表)。