Techniques

HTTP 模块

学习如何在 NestJS 中使用 HTTP 模块进行 HTTP 请求,包括 Axios 集成、配置选项和异步配置。

HTTP 模块

Axios 是一个功能丰富且广泛使用的 HTTP 客户端包。Nest 封装了 Axios 并通过内置的 HttpModule 暴露它。HttpModule 导出 HttpService 类,该类暴露基于 Axios 的方法来执行 HTTP 请求。该库还将生成的 HTTP 响应转换为 Observables

提示 您也可以直接使用任何通用的 Node.js HTTP 客户端库,包括 gotundici

安装

要开始使用它,我们首先安装所需的依赖项。

$ npm i --save @nestjs/axios axios

入门

安装过程完成后,要使用 HttpService,首先导入 HttpModule

@Module({
  imports: [HttpModule],
  providers: [CatsService],
})
export class CatsModule {}

接下来,使用正常的构造函数注入来注入 HttpService

提示 HttpModuleHttpService@nestjs/axios 包中导入。

@@filename()
@Injectable()
export class CatsService {
  constructor(private readonly httpService: HttpService) {}

  findAll(): Observable<AxiosResponse<Cat[]>> {
    return this.httpService.get('http://localhost:3000/cats');
  }
}
@@switch
@Injectable()
@Dependencies(HttpService)
export class CatsService {
  constructor(httpService) {
    this.httpService = httpService;
  }

  findAll() {
    return this.httpService.get('http://localhost:3000/cats');
  }
}

提示 AxiosResponse 是从 axios 包导出的接口($ npm i axios)。

所有 HttpService 方法都返回包装在 Observable 对象中的 AxiosResponse

配置

Axios 可以使用各种选项进行配置,以自定义 HttpService 的行为。在这里了解更多信息。要配置底层的 Axios 实例,在导入 HttpModule 时将可选的选项对象传递给 register() 方法。此选项对象将直接传递给底层的 Axios 构造函数。

@Module({
  imports: [
    HttpModule.register({
      timeout: 5000,
      maxRedirects: 5,
    }),
  ],
  providers: [CatsService],
})
export class CatsModule {}

异步配置

当您需要异步而不是静态地传递模块选项时,请使用 registerAsync() 方法。与大多数动态模块一样,Nest 提供了几种处理异步配置的技术。

一种技术是使用工厂函数:

HttpModule.registerAsync({
  useFactory: () => ({
    timeout: 5000,
    maxRedirects: 5,
  }),
});

像其他工厂提供者一样,我们的工厂函数可以是异步的,并且可以通过 inject 注入依赖项。

HttpModule.registerAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    timeout: configService.get('HTTP_TIMEOUT'),
    maxRedirects: configService.get('HTTP_MAX_REDIRECTS'),
  }),
  inject: [ConfigService],
});

或者,您可以使用类而不是工厂来配置 HttpModule,如下所示。

HttpModule.registerAsync({
  useClass: HttpConfigService,
});

上面的构造在 HttpModule 内部实例化 HttpConfigService,使用它来创建选项对象。请注意,在此示例中,HttpConfigService 必须实现 HttpModuleOptionsFactory 接口,如下所示。HttpModule 将在提供的类的实例化对象上调用 createHttpOptions() 方法。

@Injectable()
class HttpConfigService implements HttpModuleOptionsFactory {
  createHttpOptions(): HttpModuleOptions {
    return {
      timeout: 5000,
      maxRedirects: 5,
    };
  }
}

如果您想重用现有的选项提供者而不是在 HttpModule 内部创建私有副本,请使用 useExisting 语法。

HttpModule.registerAsync({
  imports: [ConfigModule],
  useExisting: HttpConfigService,
});

您还可以将所谓的 extraProviders 传递给 registerAsync() 方法。这些提供者将与模块提供者合并。

HttpModule.registerAsync({
  imports: [ConfigModule],
  useClass: HttpConfigService,
  extraProviders: [MyAdditionalProvider],
});

当您想为工厂函数或类构造函数提供额外的依赖项时,这很有用。

直接使用 Axios

如果您认为 HttpModule.register 的选项对您来说不够,或者如果您只想访问由 @nestjs/axios 创建的底层 Axios 实例,您可以通过 HttpService#axiosRef 访问它,如下所示:

@Injectable()
export class CatsService {
  constructor(private readonly httpService: HttpService) {}

  findAll(): Promise<AxiosResponse<Cat[]>> {
    return this.httpService.axiosRef.get('http://localhost:3000/cats');
    //                      ^ AxiosInstance interface
  }
}

完整示例

由于 HttpService 方法的返回值是 Observable,我们可以使用 rxjs - firstValueFromlastValueFrom 以 promise 的形式检索请求的数据。

import { catchError, firstValueFrom } from 'rxjs';

@Injectable()
export class CatsService {
  private readonly logger = new Logger(CatsService.name);
  constructor(private readonly httpService: HttpService) {}

  async findAll(): Promise<Cat[]> {
    const { data } = await firstValueFrom(
      this.httpService.get<Cat[]>('http://localhost:3000/cats').pipe(
        catchError((error: AxiosError) => {
          this.logger.error(error.response.data);
          throw 'An error happened!';
        }),
      ),
    );
    return data;
  }
}

提示 访问 RxJS 的文档了解 firstValueFromlastValueFrom 之间的差异。