Skip to content

HTTP 模块

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

提示

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

安装

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

bash
$ npm i --save @nestjs/axios axios

入门

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

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

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

提示

HttpModuleHttpService@nestjs/axios 包导入。

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

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

提示

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

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

配置

Axios 可以使用多种选项来自定义 HttpService 的行为。在这里阅读更多关于它们的信息。要配置底层的 Axios 实例,在导入时将可选的选项对象传递给 HttpModuleregister() 方法。此选项对象将直接传递给底层的 Axios 构造函数。

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

异步配置

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

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

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

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

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

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

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

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

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

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

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

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

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

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

直接使用 Axios

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

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

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

完整示例

由于 HttpService 方法的返回值是 Observable,我们可以使用 rxjsfirstValueFromlastValueFrom 以 promise 的形式获取请求的数据。

typescript
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 之间的区别。

基于 NestJS 官方文档翻译