提示: 本章節(jié)僅適用于以 HTTP 構(gòu)建的應(yīng)用程序.
接口版本可以在同一個(gè)應(yīng)用程序中的控制器或者路由層面支持 不同的版本。 應(yīng)用程序經(jīng)常更改,在仍然需要支持以前版本的應(yīng)用程序的同時(shí),需要進(jìn)行重大更改的情況并不少見(jiàn)。
Nest.js 支持一下 4 種形式的版本管理:
URI 版本類型 | 版本在請(qǐng)求的 URI 中傳遞 (默認(rèn)) |
Header 版本管理 | 在自定義的 Header 中傳遞版本 |
Media Type 版本管理 | 在 Accept 頭部標(biāo)簽中聲明版本 |
自定義版本管理 | 請(qǐng)求的任何部分都可用于指定版本,需要提供一個(gè)自定義函數(shù)來(lái)提取所述版本 |
URI 版本管理在請(qǐng)求地址中標(biāo)識(shí)版本,比如 https://example.com/v1/route 和 https://example.com/v2/route。
警告: URI 版本管理會(huì)在 全局路徑前綴 (如果存在)自動(dòng)添加版本號(hào), 并且在控制器或路由之前.
按照以下操作來(lái)使用 URI 版本管理:
@@filename(main)
const app = await NestFactory.create(AppModule);
// or "app.enableVersioning()"
app.enableVersioning({
type: VersioningType.URI,
});
await app.listen(3000);
警告: URI 版本管理默認(rèn)使用 v 前綴, 并且可以通過(guò)設(shè)置 prefix 來(lái)自定義前綴或者設(shè)置 false 來(lái)取消使用前綴行為。
提示: VersioningType 中的類型 type 是從 @nestjs/common 引入的枚舉。
Header 版本管理使用用戶指定的自定義頭部標(biāo)簽來(lái)標(biāo)明使用的請(qǐng)求版本。
使用 Header 版本管理的示例 HTTP 請(qǐng)求
按照以下步驟為你的應(yīng)用程序啟用 Header 版本管理。
@@filename(main)
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.HEADER,
header: 'Custom-Header',
});
await app.listen(3000);
header 屬性標(biāo)明要用來(lái)傳遞接口版本的頭部標(biāo)簽名。
提示: VersioningType 中的類型 type 是從 @nestjs/common 引入的枚舉。
Media 版本類型使用 Accept 頭部標(biāo)簽來(lái)聲明請(qǐng)求的版本。
在 Accept 頭部標(biāo)簽內(nèi), 版本將與媒體類型用分號(hào);分隔。它應(yīng)該包含一個(gè)鍵值對(duì),表示要用于請(qǐng)求的版本,例如 Accept: application/json;v=2。在配置包含鍵和分隔符的版本時(shí),可以設(shè)置 key 的值作為鍵的前綴值。
要為應(yīng)用程序啟用 媒體類型版本控制,請(qǐng)執(zhí)行以下操作:
@@filename(main)
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.MEDIA_TYPE,
key: 'v=',
});
await app.listen(3000);
key 屬性應(yīng)該是包含該版本的鍵值對(duì)的鍵和分隔符。在示例中 Accept: application/json;v=2,key 屬性將設(shè)置為 v=。
提示: 版本控制類型 枚舉可用于 type 屬性,并從 @nestjs/common 包中導(dǎo)入。
自定義版本控制使用請(qǐng)求的任何部分來(lái)指定一個(gè)或多個(gè)版本,并使用返回字符串或字符串?dāng)?shù)組的 extractor 函數(shù)分析傳入請(qǐng)求。
如果請(qǐng)求者提供了多個(gè)版本,則提取器函數(shù) extractor 可以返回一個(gè)字符串?dāng)?shù)組,這些字符串按最大、最高版本到最小、最低版本的順序排序,版本控制按從高到低的順序與路由匹配。
如果從 extractor 返回空字符串或數(shù)組,則不會(huì)匹配任何路由,并返回 404。
例如,如果傳入請(qǐng)求指定它支持版本 1、2 和 3,則 提取器 必須 返回 `[3, 2, 1]``,這可確保首先選擇最可能的最高路由版本。
如果提取了版本 [3, 2, 1],但僅存在版本 2 和 1 的路由,則選擇與版本 2 匹配的路由(自動(dòng)忽略版本 3)。
警告: 由于設(shè)計(jì)限制,根據(jù)從提取器 extractor 中返回的數(shù)組中選擇最高匹配版本 不能可靠地 與 Express 適配器使用,單個(gè)版本(1 個(gè)字符串或 1 個(gè)元素的數(shù)組)在 Express 中工作正常,而Fastify 能正確支持最高匹配版本選擇和單個(gè)版本選擇。
要為應(yīng)用程序啟用 自定義版本控制,請(qǐng)創(chuàng)建一個(gè) extractor 函數(shù)并將其傳遞到應(yīng)用程序中,如下所示:
@@filename(main)
// Example extractor that pulls out a list of versions from a custom header and turns it into a sorted array.
// This example uses Fastify, but Express requests can be processed in a similar way.
const extractor = (request: FastifyRequest): string | string[] =>
[request.headers['custom-versioning-field'] ?? '']
.flatMap(v => v.split(','))
.filter(v => !!v)
.sort()
.reverse()
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.CUSTOM,
extractor,
});
await app.listen(3000);
版本控制允許您對(duì)控制器、各個(gè)路由進(jìn)行版本控制,并且還為某些資源提供了一種選擇退出版本控制的方法。無(wú)論應(yīng)用程序使用哪種版本控制類型,版本控制的用法都是相同的。
警告: 如果為應(yīng)用程序啟用了版本控制,但控制器或路由未指定版本,則對(duì)該控制器、路由的任何請(qǐng)求都將返回 404 響應(yīng)狀態(tài)。同樣,如果收到的請(qǐng)求包含沒(méi)有相應(yīng)控制器或路由的版本,則還將返回 404 響應(yīng)狀態(tài)。
可以在獨(dú)立的控制器中指定版本,此設(shè)置將影響控制器下的所有路由。
參照以下添加針對(duì)單個(gè)路由的版本:
@@filename(cats.controller)
@Controller({
version: '1',
})
export class CatsControllerV1 {
@Get('cats')
findAll(): string {
return 'This action returns all cats for version 1';
}
}
@@switch
@Controller({
version: '1',
})
export class CatsControllerV1 {
@Get('cats')
findAll() {
return 'This action returns all cats for version 1';
}
}
可以在獨(dú)立的路由中指定版本,此版本將覆蓋其他影響路由的版本控制比如設(shè)置的控制器版本。
參照以下添加針對(duì)單個(gè)路由的版本:
@@filename(cats.controller)
import { Controller, Get, Version } from '@nestjs/common';
@Controller()
export class CatsController {
@Version('1')
@Get('cats')
findAllV1(): string {
return 'This action returns all cats for version 1';
}
@Version('2')
@Get('cats')
findAllV2(): string {
return 'This action returns all cats for version 2';
}
}
@@switch
import { Controller, Get, Version } from '@nestjs/common';
@Controller()
export class CatsController {
@Version('1')
@Get('cats')
findAllV1() {
return 'This action returns all cats for version 1';
}
@Version('2')
@Get('cats')
findAllV2() {
return 'This action returns all cats for version 2';
}
}
可以在控制器或路由中設(shè)置支持多版本,你需要以數(shù)組的形式設(shè)置多版本支持。
參照以下設(shè)置多版本支持
@@filename(cats.controller)
@Controller({
version: ['1', '2'],
})
export class CatsController {
@Get('cats')
findAll(): string {
return 'This action returns all cats for version 1 or 2';
}
}
@@switch
@Controller({
version: ['1', '2'],
})
export class CatsController {
@Get('cats')
findAll() {
return 'This action returns all cats for version 1 or 2';
}
}
有的控制器或路由不關(guān)心接口版本并且無(wú)論版本如何,都將具有相同的功能,為了適應(yīng)這種情況,可以將版本設(shè)置為 VERSION_NEUTRAL。
傳入的請(qǐng)求將映射到 VERSION_NEUTRAL 控制器或路由,而不管請(qǐng)求中發(fā)送的版本如何,或者請(qǐng)求中根本不包含版本信息。
警告: 對(duì)于 URI 版本控制,VERSION_NEUTRAL 不會(huì)在 URI 中指定版本信息。
要添加非特定版本控制器或路由,請(qǐng)執(zhí)行以下操作:
@@filename(cats.controller)
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
@Controller({
version: VERSION_NEUTRAL,
})
export class CatsController {
@Get('cats')
findAll(): string {
return 'This action returns all cats regardless of version';
}
}
@@switch
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
@Controller({
version: VERSION_NEUTRAL,
})
export class CatsController {
@Get('cats')
findAll() {
return 'This action returns all cats regardless of version';
}
}
如果你不想為每一個(gè)控制器或路由指定版本,或者你想為每一個(gè)控制器、路由指定默認(rèn)的版本而不指定具體的版本號(hào),你可以參照以下設(shè)置 defaultVersion:
@@filename(main)
app.enableVersioning({
// ...
defaultVersion: '1'
// or
defaultVersion: ['1', '2']
// or
defaultVersion: VERSION_NEUTRAL
});
更多建議: