如何在 NestJS 应用程序中添加请求拦截器来调用某个服务?

问题描述 投票:0回答:1

我有一个多模块 Nest 应用程序,我在其中使用

HttpModule
来执行 HTTP 请求。 在我的一项服务中,我向第三方应用程序发送请求,该应用程序每秒最多允许 3 个请求。因此,我想给这个服务使用的axios实例添加一个请求拦截器。由于 Nest 中的模块是单例,因此它们共享相同的提供程序实例,因此共享
HttpService
的相同 Axios 实例。因此,如果我修改我的提供者之一中注入的
HttpService
的 Axios 实例,例如添加一个请求拦截器 (
httpService.axiosRef.interceptors.request.use(...)
),从我的应用程序中的 any 服务发送的每个使用注入的
HttpService
的请求都将被拦截。

应用程序的示例模块结构:

// app.module.ts
@Module({
  imports: [
    ExternalIntegrationAPIModule,
    ExternalManagementAPIModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

// externalIntegrationAPI.module.ts
@Module({
  imports: [HttpModule],
  exports: [ExternalIntegrationAPIConnector],
  providers: [ExternalIntegrationAPIConnector],
})
export class ExternalIntegrationAPIModule {}

// externalIntegrationAPI.connector.ts
@Injectable()
export class ExternalIntegrationAPIConnector {
  constructor(
    private httpService: HttpService,
  ) {...}

 // ...methods that use httpService to perform requests
}

// externalManagementAPI.module.ts
@Module({
  imports: [HttpModule],
  exports: [ExternalManagementAPIConnector],
  providers: [ExternalManagementAPIConnector],
})
export class ExternalManagementAPIModule {}

// externalManagementAPI.connector.ts
@Injectable()
export class ExternalManagementAPIConnector {
  constructor(
    private httpService: HttpService,
  ) {
    // this.httpService.axiosRef.interceptors.request.use(...);
    // Since both, ExternalManagementAPIConnector and ExternalIntegrationAPIConnector
    // share the same Axios instance this would also intercept requests made from
    // ExternalIntegrationAPIConnector
  }

 // ...methods that use httpService to perform requests
}

在这种情况下,我想拦截从

ExternalManagementAPIConnector
发出的请求,以确保每秒 3 个请求的限制,同时避免拦截从
ExternalIntegrationAPIConnector
执行的任何请求。

如何添加拦截器,以便仅拦截在所需服务中执行的请求?

我尝试使用

register
HttpModule
功能来创建一个独立的Axios实例。此外,我尝试创建自己的
HttpModule
HttpService
扩展来创建独立的 Axios 实例。只要我只导入这个新模块一次,就可以了。导入此模块的每个其他模块将再次共享相同的 Axios 实例,类似于原始的行为
HttpModule

更新
我尝试使用此处提出的解决方案:NestJS:每个模块导入的 HttpModule 的新实例。 然而,一开始这也拦截了来自

TerminusModule
的健康 ping。这可以通过在我的健康服务中注入
HttpService
并将注入的 HttpService 作为配置传递来解决:

@Injectable()
class HealthService {
  constructor(
    private readonly healthCheckService: HealthCheckService,
    private readonly httpHealthIndicator: HttpHealthIndicator,
    private readonly httpService: HttpService,
    ...
  ) {...}
  async checkHealth() {
    const healthCheck = await this.healthCheckService.check([
      () => this.httpHealthIndicator.pingCheck(
              'targetKeyName',
              { httpClient: this.httpService }
            ),
      ...
    ]);
  }
}

由于在导入中使用空配置对象调用

register()
方法来创建
HttpModule
的单独实例似乎是一个 hacky 解决方案,我仍然很好奇是否还有其他干净的方法来解决我的问题。

axios nest interceptor httpmodule
1个回答
1
投票

为 HTTP 服务定义自定义提供程序并在提供程序中配置拦截器怎么样?

// externalManagementAPI.module.ts
import { HttpModule, HttpService, Module } from '@nestjs/common';
import { AxiosRequestConfig } from 'axios';

@Module({
  imports: [HttpModule],
  exports: [ExternalManagementAPIConnector],
  providers: [
    ExternalManagementAPIConnector,
    {
      provide: 'HttpServiceWithInterceptor',
      useFactory: (httpService: HttpService) => {
        const axiosInstance = httpService.axiosRef;
        axiosInstance.interceptors.request.use((config: 
AxiosRequestConfig) => {
          // interceptor logic
          // You can modify the request config or perform 
          return config;
        });

        return axiosInstance;
      },
      inject: [HttpService],
    },
  ],
})
export class ExternalManagementAPIModule {}

// externalManagementAPI.connector.ts
import { HttpService, Inject, Injectable } from '@nestjs/common';
import { AxiosInstance } from 'axios';

@Injectable()
export class ExternalManagementAPIConnector {
  constructor(
    @Inject('HttpServiceWithInterceptor')
    private httpService: AxiosInstance,
  ) {
    // You can use this.httpService to make requests with the 
interceptor applied
  }

  // methods that use httpService to perform requests
}
© www.soinside.com 2019 - 2024. All rights reserved.