应用开发完一版上线之后,还会不断的迭代。
后续可能需要修改已有的接口,但是为了兼容,之前版本的接口还要保留。
那如何同时支持多个版本的接口呢?
Nest 内置了这个功能,我们来试一下:
nest new version-test
创建个 nest 项目。
进入项目,创建 aaa 模块:
nest g resource aaa --no-spec
把服务跑起来:
npm run start:dev
postman 里访问下:
这是版本一的接口。
假设后面我们又开发了一版接口,但路由还是 aaa,怎么做呢?
这样:
在 controller 上标记为 version 1,这样默认全部的接口都是 version 1。
然后单独用 @Version 把 version 2 的接口标识一下。
在 main.ts 里调用 enableVersioning 开启接口版本功能:
import { VersioningType } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.HEADER,
header: 'version'
})
await app.listen(3000);
}
bootstrap();
开启接口版本功能,指定通过 version 这个 header 来携带版本号。
测试下:
可以看到,带上 version:1 的 header,访问的就是版本 1 的接口。
带上 version:2 的 header,访问的就是版本 2 的接口。
它们都是同一个路由。
但这时候有个问题:
如果不带版本号就 404 了。
这个也很正常,因为这就是版本一的接口嘛,只有显式声明版本才可以。
如果你想所有版本都能访问这个接口,可以用 VERSION_NEUTRAL 这个常量:
现在带不带版本号,不管版本号是几都可以访问这些接口:
但是现在因为从上到下匹配,版本 2 的接口不起作用了:
这时候或者可以把它移到上面去:
或者单独建一个 version 2 的 controller
nest g controller aaa/aaa-v2 --no-spec --flat
把 AaaController 里 version 2 的接口删掉,移到这里来:
import { Controller, Get,Version } from '@nestjs/common';
import { AaaService } from './aaa.service';
@Controller({
path: 'aaa',
version: '2'
})
export class AaaV2Controller {
constructor(private readonly aaaService: AaaService) {}
@Get()
findAllV2() {
return this.aaaService.findAll() + '222';
}
}
现在版本 2 就走的 AaaV2Controller:
其他版本走 AaaController:
一般我们就是这样做的,有一个 Controller 标记为 VERSION_NEUTRAL,其他版本的接口放在单独 Controller 里。
注意,controller 之间同样要注意顺序,前面的 controller 先生效:
试一下:
除了用自定义 header 携带版本号,还有别的方式:
app.enableVersioning({
type: VersioningType.MEDIA_TYPE,
key: 'vv='
})
MEDIA_TYPE 是在 accept 的 header 里携带版本号:
你也可以用 URI 的方式:
app.enableVersioning({
type: VersioningType.URI
})
但是这种方式不支持 VERSION_NEUTRAL,你要指定明确的版本号才可以:
此外,如果觉得这些指定版本号的方式都不满足需求,可以自己写:
import { VersioningType } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Request } from 'express';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const extractor = (request: Request)=> {
if(request.headers['disable-custom']) {
return '';
}
return request.url.includes('guang') ? '2' : '1';
}
app.enableVersioning({
type: VersioningType.CUSTOM,
extractor
})
await app.listen(3000);
}
bootstrap();
我们自己实现了一个版本号的逻辑,如果 url 里包含 guang,就返回版本 2 的接口,否则返回版本 1 的。
此外,如果有 disable-custom 的 header 就返回 404。
试一下:
这样,就能实现各种灵活的版本号规则。
案例代码在小册仓库。
总结
今天我们学了如何开发一个接口的多个版本。
Nest 内置了这个功能,同一个路由,指定不同版本号就可以调用不同的接口。
只要在 main.ts 里调用 enableVersioning 即可。
有 URI、HEADER、MEDIA_TYPE、CUSTOM 四种指定版本号的方式。
HEADER 和 MEDIA_TYPE 都是在 header 里置顶,URI 是在 url 里置顶,而 CUSTOM 是自定义版本号规则。
可以在 @Controller 通过 version 指定版本号,或者在 handler 上通过 @Version 指定版本号。
如果指定为 VERSION_NEUTRAL 则是匹配任何版本号(URI 的方式不支持这个)。
这样,当你需要开发同一个接口的多个版本的时候,就可以用这些内置的功能。