在NestJS中实现基于请求头的版本检测——使用拦截器实现
- 1220字
- 6分钟
- 2024-09-14
在最近的一个项目中,我们需要为API添加版本控制功能,以确保不同版本的客户端能够兼容接口变化,同时在需要时向旧版客户端提示更新。这种需求在移动端开发中很常见,通常客户端会通过HTTP请求的header发送当前版本号,服务器再根据版本号返回相应的响应数据。
我们遇到的问题是,在某些情况下,当客户端版本过旧时,我们希望能够在正常的返回数据中附加一些更新提示信息,这样能在接口请求端统一处理该逻辑,而不需要改动原有的业务逻辑。为了解决这一问题,我们可以选择在NestJS中使用拦截器或者中间件来实现。
本文以拦截器为例,带大家实现一遍该需求。对于中间件的实现,可以参考这篇文章:《在NestJS中实现基于请求头的版本检测——使用中间件实现》
需求分析
需求很简单:在每个请求的header中携带客户端版本号,服务器根据这个版本号进行检测。如果客户端的版本低于服务器要求的最新版本,就需要在响应中附加一个更新提示字段;如果版本符合要求,则正常返回数据而不做修改。
如何实现
在NestJS中,我们可以通过拦截器来捕获请求和响应。在拦截器中,我们可以:
- 获取请求头中的版本信息。
- 判断版本是否需要更新,通过简单的版本号比较实现。
- 修改响应数据,如果需要更新,在返回数据中添加额外的字段。
1. 创建版本检测拦截器
拦截器是NestJS中用于拦截请求和响应的重要工具。在这个场景下,我们需要创建一个拦截器,负责在响应数据发回客户端之前,对其进行版本检测和处理。
1import {2 CallHandler,3 ExecutionContext,4 Injectable,5 NestInterceptor,6} from "@nestjs/common";7import { Observable } from "rxjs";8import { map } from "rxjs/operators";9
10@Injectable()11export 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中应用这个拦截器:局部应用或全局应用。
局部应用拦截器
如果只需要在某些特定路由上使用版本检测功能,可以在相应的控制器中应用拦截器。
1import { Controller, Get, UseInterceptors } from "@nestjs/common";2import { VersionInterceptor } from "./version.interceptor";3
4@Controller("api")5export class AppController {6 @Get("data")7 @UseInterceptors(VersionInterceptor)8 getData() {9 return {10 data: "Here is your data",11 };12 }13}
全局应用拦截器
如果希望所有API接口都支持版本检测,可以通过 main.ts
将拦截器全局应用。
1import { NestFactory } from "@nestjs/core";2import { AppModule } from "./app.module";3import { VersionInterceptor } from "./version.interceptor";4
5async function bootstrap() {6 const app = await NestFactory.create(AppModule);7
8 // 全局使用拦截器9 app.useGlobalInterceptors(new VersionInterceptor());10
11 await app.listen(3000);12}13bootstrap();
3. 测试接口
在完成拦截器的设置后,我们可以通过 curl
或 Postman 来测试接口。客户端通过请求头发送版本信息,服务器将根据版本号返回相应的响应。
请求示例
1curl -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的兼容性,同时确保旧版本的客户端能及时获取到更新提示,提升了用户体验。


