在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的兼容性,同時確保舊版本的客戶端能及時獲取到更新提示,提升了用戶體驗。