压缩与版本控制
本教程共 47 篇 · 第 35 篇 · 更新于 2026-08-09 · 约 9 分钟阅读
本节目标:学会给 API 响应开启压缩以减小传输体积,以及用版本控制让新旧接口和平共存。
响应压缩
你的接口返回一个 JSON,可能也就几 KB。但如果返回的是列表数据、HTML 页面或者大段文本,体积就上去了。
压缩就是在服务端把响应体压一下,客户端收到后自动解压。对用户来说完全透明,但传输体积能缩小 60%-80%。
Express 项目
用 compression 这个中间件:
npm install compression
npm install -D @types/compression
在 main.ts 里启用:
import * as compression from 'compression';
// 在 app 创建之后、listen 之前
app.use(compression());
就这么简单。所有经过 Express 的响应都会自动 gzip 压缩。
Fastify 项目
Fastify 用的是 @fastify/compress:
npm install @fastify/compress
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import compression from '@fastify/compress';
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.register(compression);
NoteFastify 的压缩插件默认会用 Brotli 算法(Node >= 11.7),压缩率比 gzip 高,但速度更慢。如果你更在意响应速度,可以指定只用 gzip:
await app.register(compression, { encodings: ['gzip', 'deflate'] });
什么时候不该用应用层压缩
如果你的应用前面有 Nginx 反向代理,压缩应该交给 Nginx 做,不要在应用层做。Nginx 是 C 写的,压缩效率比 Node.js 高很多。
应用层压缩适合这些场景:
- 没有反向代理,直接暴露 Node.js 服务
- 开发调试阶段
- 某些特殊路由需要定制化压缩策略
Tip生产环境最佳实践:Nginx 负责压缩,Node.js 应用不装 compression 中间件。这样应用进程可以把 CPU 留给业务逻辑。
API 版本控制
接口上线后,你不能随便改。前端可能还在用旧版接口,移动端 app 用户不会立刻更新。直接改接口等于砸别人的饭碗。
版本控制就是给接口加上版本号,新旧版本同时存在,给调用方足够的迁移时间。
启用版本控制
在 main.ts 里开启:
import { VersioningType } from '@nestjs/common';
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI,
});
VersioningType.URI 是最常用的方式——版本号直接出现在 URL 里:
GET /v1/cats
GET /v2/cats
四种版本控制方式
| 类型 | 说明 | 示例 |
|---|---|---|
| URI | 版本号在 URL 路径里 | /v1/cats |
| Header | 自定义请求头指定版本 | Custom-Version: 1 |
| Media Type | Accept 头里指定版本 | Accept: application/json;v=2 |
| Custom | 你自己写提取函数 | 任意逻辑 |
Header 版本控制:
app.enableVersioning({
type: VersioningType.HEADER,
header: 'X-Api-Version',
});
客户端请求时带上 X-Api-Version: 1 就行。
Media Type 版本控制:
app.enableVersioning({
type: VersioningType.MEDIA_TYPE,
key: 'v=',
});
客户端请求头:Accept: application/json;v=2
Custom 版本控制:
const extractor = (req: Request): string | string[] => {
// 你想从哪取就从哪取
return req.headers['x-api-version'] as string;
};
app.enableVersioning({
type: VersioningType.CUSTOM,
extractor,
});
TipURI 版本控制最直观,前端调试也方便。大部分公开 API(微信、支付宝、Stripe)都用这种方式。没特殊需求就选它。
在控制器上使用版本
启用了版本控制后,控制器需要声明自己属于哪个版本:
@Controller({
version: '1',
})
export class CatsControllerV1 {
@Get('cats')
findAll(): string {
return '这是 v1 的猫咪接口';
}
}
请求 /v1/cats 会命中这个控制器。请求 /v2/cats 会返回 404,因为没有 v2 的控制器。
在路由上使用版本
如果同一个控制器里不同路由版本不同,可以在方法级别声明:
import { Controller, Get, Version } from '@nestjs/common';
@Controller()
export class CatsController {
@Version('1')
@Get('cats')
findAllV1(): string {
return 'v1 版本';
}
@Version('2')
@Get('cats')
findAllV2(): string {
return 'v2 版本,返回了更多数据';
}
}
路由级别的版本会覆盖控制器级别的。
一个控制器支持多个版本
如果 v1 和 v2 的逻辑完全一样,不用写两份:
@Controller({
version: ['1', '2'],
})
export class CatsController {
@Get('cats')
findAll(): string {
return 'v1 和 v2 共用这个逻辑';
}
}
版本中立
有些接口不需要版本控制——不管客户端请求哪个版本,都返回同样的内容。用 VERSION_NEUTRAL:
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
@Controller({
version: VERSION_NEUTRAL,
})
export class HealthController {
@Get('health')
check(): string {
return 'ok';
}
}
NoteURI 版本控制下,
VERSION_NEUTRAL的接口 URL 里不会出现版本号。比如/health而不是/v1/health。
全局默认版本
不想每个控制器都写版本号?设一个全局默认版本:
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
});
这样没声明版本的控制器自动归到 v1。
中间件也支持版本
中间件可以指定只对某个版本生效:
@Module({})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({
path: 'cats',
method: RequestMethod.GET,
version: '2',
});
}
}
这个 LoggerMiddleware 只在请求 v2 的 /cats 时才会执行。
小结
压缩:
- Express 用
compression中间件,Fastify 用@fastify/compress - 有 Nginx 反代的话,压缩交给 Nginx 做
- Fastify 默认 Brotli,可以指定只用 gzip 提速
版本控制:
app.enableVersioning()开启,默认 URI 方式- 控制器用
version: '1',路由用@Version('1') VERSION_NEUTRAL让接口忽略版本defaultVersion设全局默认版本,省得每个控制器都写