在NestJS中实现基于请求头的版本检测——使用拦截器实现

在最近的一个项目中,我们需要为API添加版本控制功能,以确保不同版本的客户端能够兼容接口变化,同时在需要时向旧版客户端提示更新。这种需求在移动端开发中很常见,通常客户端会通过HTTP请求的header发送当前版本号,服务器再根据版本号返回相应的响应数据。

我们遇到的问题是,在某些情况下,当客户端版本过旧时,我们希望能够在正常的返回数据中附加一些更新提示信息,这样能在接口请求端统一处理该逻辑,而不需要改动原有的业务逻辑。为了解决这一问题,我们可以选择在NestJS中使用拦截器或者中间件来实现。

本文以拦截器为例,带大家实现一遍该需求。对于中间件的实现,可以参考这篇文章:《在NestJS中实现基于请求头的版本检测——使用中间件实现》

需求分析

需求很简单:在每个请求的header中携带客户端版本号,服务器根据这个版本号进行检测。如果客户端的版本低于服务器要求的最新版本,就需要在响应中附加一个更新提示字段;如果版本符合要求,则正常返回数据而不做修改。

如何实现

在NestJS中,我们可以通过拦截器来捕获请求和响应。在拦截器中,我们可以:

  1. 获取请求头中的版本信息
  2. 判断版本是否需要更新,通过简单的版本号比较实现。
  3. 修改响应数据,如果需要更新,在返回数据中添加额外的字段。

1. 创建版本检测拦截器

拦截器是NestJS中用于拦截请求和响应的重要工具。在这个场景下,我们需要创建一个拦截器,负责在响应数据发回客户端之前,对其进行版本检测和处理。

1
import {
2
CallHandler,
3
ExecutionContext,
4
Injectable,
5
NestInterceptor,
6
} from "@nestjs/common";
7
import { Observable } from "rxjs";
8
import { map } from "rxjs/operators";
9
10
@Injectable()
11
export class VersionInterceptor implements NestInterceptor {
12
private readonly latestVersion = "2.0.0"; // 设定最新版本号
13
14
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
15
const request = context.switchToHttp().getRequest();
16
const version = request.headers["version"]; // 从header中获取版本号
17
18
return next.handle().pipe(
19
map((data) => {
20
if (version && this.needsUpdate(version)) {
21
// 如果需要更新,则添加额外字段
22
return {
23
...data,
24
updateAvailable: true,
25
updateUrl: "xxxx", // 更新地址
26
latestVersion: this.latestVersion,
27
message: "A new version is available, please update.",
28
};
29
}
30
// 不需要更新,直接返回原始响应数据
31
return data;
32
}),
33
);
34
}
35
36
// 版本比较逻辑
37
private needsUpdate(clientVersion: string): boolean {
38
return clientVersion < this.latestVersion;
39
}
40
}

在这个拦截器中,我们通过 request.headers['version'] 获取客户端传来的版本号,并调用 needsUpdate 方法进行版本比较。如果客户端版本较低,我们将额外的 updateAvailable 字段插入到返回数据中,告知用户有新版本可用。

2. 应用拦截器

有两种方式可以在NestJS中应用这个拦截器:局部应用或全局应用。

局部应用拦截器

如果只需要在某些特定路由上使用版本检测功能,可以在相应的控制器中应用拦截器。

1
import { Controller, Get, UseInterceptors } from "@nestjs/common";
2
import { VersionInterceptor } from "./version.interceptor";
3
4
@Controller("api")
5
export class AppController {
6
@Get("data")
7
@UseInterceptors(VersionInterceptor)
8
getData() {
9
return {
10
data: "Here is your data",
11
};
12
}
13
}

全局应用拦截器

如果希望所有API接口都支持版本检测,可以通过 main.ts 将拦截器全局应用。

1
import { NestFactory } from "@nestjs/core";
2
import { AppModule } from "./app.module";
3
import { VersionInterceptor } from "./version.interceptor";
4
5
async function bootstrap() {
6
const app = await NestFactory.create(AppModule);
7
8
// 全局使用拦截器
9
app.useGlobalInterceptors(new VersionInterceptor());
10
11
await app.listen(3000);
12
}
13
bootstrap();

3. 测试接口

在完成拦截器的设置后,我们可以通过 curl 或 Postman 来测试接口。客户端通过请求头发送版本信息,服务器将根据版本号返回相应的响应。

请求示例

Terminal window
1
curl -X GET http://localhost:3000/api/data -H "version: 1.0.0"

响应示例(需要更新时)

1
{
2
"data": "Here is your data",
3
"updateAvailable": true,
4
"latestVersion": "2.0.0",
5
"message": "A new version is available, please update."
6
}

响应示例(不需要更新时)

1
{
2
"data": "Here is your data"
3
}

总结

拦截器是处理版本检测的一个非常高效且灵活的工具,它能够在不修改控制器逻辑的情况下,动态地修改响应数据,从而根据客户端版本返回不同的提示信息。这个方法不仅适用于版本控制,也适用于其他类似场景,比如对响应内容进行全局格式化或添加额外的元数据。

这种方法能够帮助我们维护API的兼容性,同时确保旧版本的客户端能及时获取到更新提示,提升了用户体验。

美团外卖红包 饿了么红包 支付宝红包