点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 10:33 更新文章,每天掉亿点点头发...
源码精品专栏
在实际项目开发中我们经常需要对接口进行版本管理。那今天我们就来聊聊为什么需要版本控制,以及如何对REST API进行版本控制。我们将讨论4种版本控制的方法,并比较不同的方法。
通过此文您将学到
为什么我们需要对RESTful API 进行版本控制?
可用的版本控制有哪些?
如何实现基于 Restful 的版本控制?
为什么我们需要对RESTful API进行版本化
最好的版本控制方法是不进行版本控制。只要不需要版本控制,就不要版本控制。
““
构建向后兼容的服务,以便尽可能避免版本控制!
”
然而,在许多情况下我们都需要进行版本控制,然我们看看下面具体的例子:
最初,你有个这个版本的Student服务,返回数据如下:
{
"name": "Bob Charlie"
}
后来,您希望将学生的名字拆分,因此创建了这个版本的服务。
{
"name": {
"firstName": "Bob",
"lastName": "Charlie"
}
}
您可以从同一个服务支持这两个请求,但是随着每个版本的需求多样化,它会变得越来越复杂。
在这种情况下,版本控制就成必不可少,强制性的了。
接下来让我们创建一个简单的SpringBoot的maven项目,并理解对 RESTful 服务进行版本控制的4种不同方法。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
几个用于实现版本控制的Bean
第一个版本的 Bean
@Data
@AllArgsConstructor
public class StudentV1 {
private String name;
}
第二个版本的 Bean
@Data
public class StudentV2 {
private Name name;
}
StudentV2使用的Name实体
@Data
@AllArgsConstructor
public class Name {
private String firstName;
private String lastName;
}
“推荐下自己做的 Spring Boot 的实战项目:
https://github.com/YunaiV/ruoyi-vue-pro
Restful 版本控制的方法
我们希望创建两个版本的服务,一个返回 StudentV1,另一个返回 StudentV2。
让我们来看看创建相同服务版本的4种不同方法。
通过 URI 进行版本控制
@RestController
public class StudentUriController {
@GetMapping("v1/student")
public StudentV1 studentV1() {
return new StudentV1("javadaily");
}
@GetMapping("v2/student")
public StudentV2 studentV2() {
return new StudentV2(new Name("javadaily", "JAVA日知录"));
}
}
请求:http://localhost:8080/v1/student
响应:{"name":"javadaily"}
请求:http://localhost:8080/v2/student
响应:{"name":{"firstName":"javadaily","lastName":"JAVA日知录"}}
通过请求参数进行版本控制
版本控制的第二种方法是使用请求参数来区分版本。请求示例如下所示:
http://localhost:8080/student/param?version=1
http://localhost:8080/student/param?version=2
实现方式如下:
@RestController
public class StudentParmController {
@GetMapping(value="/student/param",params = "version=1")
public StudentV1 studentV1() {
return new StudentV1("javadaily");
}
@GetMapping(value="/student/param",params = "version=2")
public StudentV2 studentV2() {
return new StudentV2(new Name("javadaily", "JAVA日知录"));
}
}
请求:http://localhost:8080/student/param?version=1
响应:{"name":"javadaily"}
请求:http://localhost:8080/student/param?version=2
响应:{"name":{"firstName":"javadaily","lastName":"JAVA日知录"}}
通过自定义Header进行版本控制
版本控制的第三种方法是使用请求头来区分版本,请求示例如下:
http://localhost:8080/student/header
headers=[X-API-VERSION=1]
http://localhost:8080/student/header
headers=[X-API-VERSION=2]
实现方式如下所示:
@RestControllerpublic class StudentHeaderController { @GetMapping(value="/student/header",headers = "X-API-VERSION=1") public StudentV1 studentV1() { return new StudentV1("javadaily"); } @GetMapping(value="/student/header",headers = "X-API-VERSION=2") public StudentV2 studentV2() { return new StudentV2(new Name("javadaily", "JAVA日知录")); }}
下图展示了我们如何使用Postman执行带有请求头的Get请求方法。
请求:http://localhost:8080/student/header
header:X-API-VERSION = 1
![3fc86ac90ae7ddccf58ff255685caf40.png](https://i-blog.csdnimg.cn/blog_migrate/14e03ff3c650066f955d7cfecadd61cd.png)
请求:http://localhost:8080/student/header
header:X-API-VERSION = 2
![435f640f7b61ae7df7e29876146781b8.png](https://i-blog.csdnimg.cn/blog_migrate/1f00b4031f792295d0339e46b19a0888.png)
通过媒体类型进行版本控制
最后一种版本控制方法是在请求中使用Accept Header,请求示例如下:
http://localhost:8080/student/produce
headers=[Accept=application/api-v1+json]
http://localhost:8080/student/produce
headers=[Accept=application/api-v2+json]
实现方式如下:
@RestController
public class StudentProduceController {
@GetMapping(value="/student/produce",produces = "application/api-v1+json")
public StudentV1 studentV1() {
return new StudentV1("javadaily");
}
@GetMapping(value="/student/produce",produces = "application/api-v2+json")
public StudentV2 studentV2() {
return new StudentV2(new Name("javadaily", "JAVA日知录"));
}
}
下图展示了我们如何使用Postman执行带有请求Accept的Get方法。
请求:http://localhost:8080/student/produce
header:Accept = application/api-v1+json
![d8fe20baf0316072523407c742cddb46.png](https://i-blog.csdnimg.cn/blog_migrate/1a3d2cdc9b748e198e3a3e919ac0d49c.png)
请求:http://localhost:8080/student/produce
header:Accept = application/api-v2+json
![d4c4549c2413a26c54a256675d0941e9.png](https://i-blog.csdnimg.cn/blog_migrate/ccfd93192218e78bec61bce3d3d885e1.png)
“推荐下自己做的 Spring Cloud 的实战项目:
https://github.com/YunaiV/onemall
影响版本选择的因素
以下因素影响版本控制的选择
URI 污染 - URL版本和请求参数版本控制会污染URI空间。
滥用请求头 - Accept 请求头并不是为版本控制而设计的。
缓存 - 如果你使用基于头的版本控制,我们不能仅仅基于URL缓存,你需要考虑特定的请求头。
是否能在浏览器直接执行 ? - 如果您有非技术消费者,那么基于URL的版本将更容易使用,因为它们可以直接在浏览器上执行。
API文档 - 如何让文档生成理解两个不同的url是同一服务的版本?
““
事实上,并没有完美的版本控制解决方案,你需要根据项目实际情况进行选择。
”
下面列表展示了主要API提供商使用的不同版本控制方法:
媒体类型的版本控制
Github
自定义Header
Microsoft
URI路径
Twitter,百度,知乎
请求参数控制
Amazon
好了,今天的文章就到这里了,希望能对你有所帮助。
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)