由于工作需要礁苗,需要對所有的Http請求添加統(tǒng)一的攔截器爬凑。查了不少文檔,繞了不少彎路试伙,也get到不少東西嘁信,特此記錄下。
搜了很多資料疏叨,大多數(shù)答案如下:
export class AppModule implements OnModuleInit {
constructor(private httpService: HttpService) { }
public onModuleInit() {
this.httpService.axiosRef.interceptors.request.use((req) => {
console.log('request', req);
return req;
})
this.httpService.axiosRef.interceptors.response.use((response) => {
console.log('response', response);
return response;
});
}
}
先不管這種解決方案是否正確潘靖,我們先來看下這部分代碼里面的知識點:
生命周期
同react一樣,nest.js中也存在生命周期蚤蔓,如圖所示:
簡單介紹下
鉤子方法 | 觸發(fā)鉤子方法調(diào)用的生命周期事件 |
---|---|
OnModuleInit | 初始化主模塊后調(diào)用 |
OnApplicationBootstrap | 在應(yīng)用程序完全啟動并引導(dǎo)后調(diào)用 |
OnModuleDestroy | 在Nest銷毀主模塊(app.close()方法之前進行清理) |
beforeApplicationShutdown | 在調(diào)用OnModuleDestroy()完成后(promise或者reject)觸發(fā) |
OnApplicationShutdown | 響應(yīng)系統(tǒng)信號(當(dāng)應(yīng)用程序關(guān)閉時卦溢,例如SIGTERM) |
具體參考官網(wǎng)介紹
添加攔截器
由于Nest.js的HttpModule模塊底層使用的是axios,所以對HttpModule添加攔截器秀又,實際就是對axios添加攔截器单寂。看下面代碼:
axios.interceptors.request.use(function (config) {
// 在發(fā)送請求之前做些什么
//config是axios請求的參數(shù)
return config;
}, function (error) {
// 對請求錯誤做些什么
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
// 對響應(yīng)數(shù)據(jù)做點什么
// response 是請求回來的數(shù)據(jù)
return response;
}, function (error) {
// 對響應(yīng)錯誤做點什么
return Promise.reject(error)
}
)
所以在Nest.js中對axios添加就有了如下代碼:
this.httpService.axiosRef.interceptors.request.use((req) => {
console.log('request', req);
return req;
})
this.httpService.axiosRef.interceptors.response.use((response) => {
console.log('response', response);
return response;
});
結(jié)合上面兩個知識點吐辙,我們就能看懂最初的那段代碼了凄贩。它就是想在AppModule啟動的時候,統(tǒng)一對httpService添加攔截器袱讹。
想法是好的疲扎,現(xiàn)實卻很殘酷昵时,我試了很久都不行,于是繼續(xù)搜椒丧,直接在一個issue中找到了一樣的代碼以及Nest開發(fā)人員的回復(fù)
Issue及回答
按照官方回答壹甥,將第一段代碼遷入到單獨的Module下面,果然就能攔截到請求壶熏。
可是這樣實在太麻煩句柠,每次都要寫一坨代碼。
于是就想到注入的方式棒假,搜了下github溯职,果然有人實現(xiàn)了。nest-axios-interceptor
下來我們基于它帽哑,來寫個攔截器谜酒,實現(xiàn)記錄axios請求響應(yīng)時間的功能。
import { HttpService, Injectable } from '@nestjs/common'
import type { AxiosRequestConfig } from 'axios'
import {
AxiosInterceptor,
AxiosFulfilledInterceptor,
AxiosRejectedInterceptor,
AxiosResponseCustomConfig,
} from '@narando/nest-axios-interceptor'
// logging.axios-interceptor.ts
const LOGGING_CONFIG_KEY = Symbol('kLoggingAxiosInterceptor')
// Merging our custom properties with the base config
interface LoggingConfig extends AxiosRequestConfig {
[LOGGING_CONFIG_KEY]: {
startTime: number
}
}
@Injectable()
export class LoggingAxiosInterceptor extends AxiosInterceptor<LoggingConfig> {
constructor(httpService: HttpService) {
super(httpService)
}
requestFulfilled(): AxiosFulfilledInterceptor<LoggingConfig> {
return (config) => {
config[LOGGING_CONFIG_KEY] = {
startTime: Date.now(),
}
return config
}
}
// requestRejected(): AxiosRejectedInterceptor {}
responseFulfilled(): AxiosFulfilledInterceptor<
AxiosResponseCustomConfig<LoggingConfig>
> {
return (res) => {
const startTime = res.config[LOGGING_CONFIG_KEY].startTime
const endTime = Date.now()
const duration = endTime - startTime
const log = `axios調(diào)用接口路由:${res.config.url};請求時間: ${duration}ms`
console.log(log)
return res
}
}
}
最后就是如何注入攔截器了,把它放進module的providers即可
import { Module, HttpModule } from '@nestjs/common'
import { ExampleController } from '../controller/index.controller'
import { ExampleService } from '../service/index.service'
import { LoggingAxiosInterceptor } from 'xxxx/axios.interceptor'
/**
* 示例模塊
*/
@Module({
imports: [HttpModule.register({})],
controllers: [ExampleController],
providers: [LoggingAxiosInterceptor, ExampleService],
})
export class ExampleModule {}