前言
nestjs 开发迭代版本时,也会碰到其他后端碰到的问题,那就是版本迭代,有时候可能会兼容一下就行了,有时会进行破坏性更新,那么我们可能要被迫分开接口来进行我们的操作,常见的就是添加版本参数
判断操作了
添加版本参数主要有两种手段,一种加入到 uri 中,一种 header 中(当然还有更简简单粗暴的手段,直接换一个url,后面介绍)
其中加入到 uri 中,就是我们的接口url中要添加拼接一个版本号,挺常见;另一种就是放到 header 中,这个更是很常见,我们的设备类型(android、ios、web、小程序类型一般都是放到这里吧),因此 header 方案也是比较推荐
的
另外也会谈谈个人的小见解
设置版本控制
URI 类型
将版本设置到 uri 中,也是比较推荐的
,需要注意的是,版本参数
放到我们的 api 前缀 后面
,如果没有前缀,则直接加到域名后面就行了
js
app.enableVersioning({
type: VersioningType.URI,
});
//实际访问的url在 api 前缀之后加上版本号 v1(v+版本号)
http://localhost:4000/api/v1/order/create
//如果是设置了中立,就不需要加入版本号了
http://localhost:4000/api/order/create
Header 类型
将版本设置到 header 中,也是比较推荐的
js
app.enableVersioning({
type: VersioningType.HEADER,
header: 'Api-Version', //自己起名字,别重复就行
});
只需要在请求的header中加入 Api-Version 1 即可,直接传入版本号即可
媒体类型 Accpet
设置到媒体类型 Accpet 中,不是很常见
js
app.enableVersioning({
type: VersioningType.MEDIA_TYPE,
key: 'v=',
});
这个传递时需要设置 Accept,这个参数会默认设置一下可以这么用,用的比较少
Accept: application/json;v=2
这个使用一个案例吧,如需哦啊所示,后面拼上 v=版本号
应用版本号到路由
可以直接设置版本号到控制器,也可以设置版本号到指定路由器,这样指定版本的就都可以访问了,可以设置支持一个或多个版本,
可以根据版本分成两个处理方法,毕竟有些版本确实存在破坏性修改,但是老的也不能抛弃;也有的直接连续支持好几个版本,直接一次多个
当然没有版本疑虑的可以直接不声明版本类型,这样都可以访问,在需要时在分离,只需要加上版本号兼容即可
js
@Version('1')
@Controller('version')
// @Controller({
// version: VERSION_NEUTRAL, //中立,在没有版本控制的路由上不需要拼接url了(主要针对于url版本)
// })
export class VersionController {
constructor(private readonly versionService: VersionService) {}
@Version('1')
@Get('test')
test1() {
return '测试版本1';
}
@Version('2')
@Get('test')
test2() {
return '测试版本2';
}
@Version(['1', '2'])
@Get('test2')
test3() {
return '测试版本1-2';
}
}
问题
上面的方便是方便,可是问题也是很多,例如:
我们的 uri 版本发现 swagger 支持不太理想,复制了url不能直接用,还要手动改,很麻烦,且会看不到多个版本不同的参数信息
headers 需要传递隐藏的版本信息,编写swagger文档也得额外标记,并且接口也要经常传递版本信息,无论是使用 swagger 还是前端手动传递都是很不方便
因此这个默认的版本,除非对 nestjs 依赖过强,否则个人是很不推荐的
,包括上面三种方式
结论
:上面三种都很不好用,直接抛弃最好
个人以前曾经看过一些其他语言的接口写的接口,发现了一个很综合且很好用的方案,因为发现,当综合思考过后,最后都会走向同一个岔路口!
无论是使用方便,还是swagger文档看着方便,那毫无疑问就是 url 方案了,只不过跟上面的稍微不一样罢了
新的方案(简单易懂-力推)
我们在版本控制时,最常见的问题就是,新老版本的使用问题,对于那些版本没变化的,不用管就行,因此我们直接使用最原始的方案
即可,手动处理
我们平时编写时,无需考虑版本问题,也不需要要额外配置,就正常开发
当我们需要新的版本时,如果老版本可以直接删了这种的,直接重写就好
我们可能对于老版本有所破坏,也就是新增加、搞懂了一些功能,但同时老功能还需要保持原样的,这样的问题比较多
此时我们可以不动老接口
,直接添加一个新的接口
,新接口前面加上前缀 v1(v+版本号)
js
//我们老接口
@Get('test2')
Test2() {
return '版本v1版本';
}
//新接口
@Get('v2/test2')
superTest2() {
return '强化版本v2';
}
//如果全改了,那么直接这样即可
@Controller('version/v2')
export class VersionController {}
看到上面我们可能就恍然大悟,就这么简单就区分开了,不仅使用上没有什么难度,并且接口文档也无需太大改变,只需要新版本的接口url添加一个版本信息即可
对于需要增加版本,可以分接口,也可以不分开,老的代码是可以提取出来的是吧,service 之间也可以通信是吧,这不代码也能更好得分离出来
对于在新版本之上,在增加新的版本,那么我们只需要老代码保持原样就行了,继续新增一个接口即可,老接口 v1 变成 v2 即可,可能有些接口更新到了v8版本,有些才 v2,不用管,没有升级的,就以最新一次更新的版本号为基准使用即可(也就是保持原样,根本不需要动即可)
就这样我们的版本控制方案了,简单粗暴(前面有提到的就是这种哈)
最后
我们编写代码时,如果有些不方便,不妨停下来思考一下,并不是说一些社区推荐给我们的就是最好的,或者最适合我们的,如果能一次性开发出终极版本,那么现实中也不会存在那么多版本的应用了
总结:就是在使用一个方案时,要看到他的优缺点,而不是直接就上到自己的应用中,可以斟酌一下,有不足如果能改善,也算提升一下自己了哈
最后,思考和学习能够让自己收获更多,一起进步吧