首页 / NestJS 入门教程 / HTTP模块

NestJS 入门教程

HTTP模块

本教程共 47 篇 · 第 33 篇 · 更新于 2026-08-09 · 约 8 分钟阅读

NestJSHTTP模块HttpServiceAxiosObservable

本节目标:学会用 NestJS 的 HttpModule 调用外部 API,掌握配置、错误处理和 Observable 的使用。

为什么需要 HTTP 模块

你的应用经常需要调第三方接口——微信支付、短信服务、天气 API。这些请求不是你的服务提供的,而是你主动发出去的。

你可以直接用 fetch 或者 axios,但 NestJS 帮你封装了一层,把 Axios 包装成了 HttpService,并且跟依赖注入体系打通了。

好处是什么?配置统一管理、测试时方便 mock、跟 NestJS 的模块系统无缝集成。

安装

HTTP 模块也是独立包:

npm install @nestjs/axios axios

需要装两个包——@nestjs/axios 是 NestJS 的封装层,axios 是底层引擎。

基本用法

先在模块里导入 HttpModule

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { CatsService } from './cats.service';

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

然后在服务里注入 HttpService 就能用了:

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Observable } from 'rxjs';
import { AxiosResponse } from 'axios';

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

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

注意返回值——HttpService 的方法返回的是 Observable,不是 Promise。这是跟直接用 axios 最大的区别。

Observable 还是 Promise

很多人刚接触会觉得别扭——我就想要个 Promise 怎么办?

用 RxJS 的 firstValueFrom 转一下就行:

import { firstValueFrom } from 'rxjs';

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

  async findAll(): Promise<any[]> {
    const { data } = await firstValueFrom(
      this.httpService.get<any[]>('http://localhost:3000/cats'),
    );
    return data;
  }
}

firstValueFrom 会在 Observable 发出第一个值后 resolve,行为跟 Promise 一样。

Tip

如果你的方法本身就是 async 的,用 firstValueFrom 转成 Promise 更自然。如果你需要用到 RxJS 的操作符(重试、过滤、map),那就保持 Observable 更灵活。

配置 HttpModule

通过 register 方法可以传入 Axios 的配置项:

@Module({
  imports: [
    HttpModule.register({
      timeout: 5000,       // 请求超时 5 秒
      maxRedirects: 5,     // 最多重定向 5 次
      headers: {
        'X-Api-Key': 'your-api-key',
      },
    }),
  ],
  providers: [CatsService],
})
export class CatsModule {}

这些配置会传给底层的 Axios 实例,跟直接用 axios 创建实例时的配置一模一样。

异步配置

实际项目中,超时时间、API 地址这些通常放在配置文件里。用 registerAsync 就能动态读取:

@Module({
  imports: [
    HttpModule.registerAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        timeout: configService.get<number>('HTTP_TIMEOUT'),
        maxRedirects: configService.get<number>('HTTP_MAX_REDIRECTS'),
        baseURL: configService.get<string>('API_BASE_URL'),
      }),
      inject: [ConfigService],
    }),
  ],
  providers: [CatsService],
})
export class CatsModule {}

useFactory 支持异步,也支持注入其他依赖。跟前面学过的动态模块写法完全一致。

你也可以用 class 的方式来提供配置:

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

// 模块中
HttpModule.registerAsync({
  useClass: HttpConfigService,
});
Note

useClass 会在模块内部创建一个 HttpConfigService 的实例。如果你想复用已有的 provider 而不是新建一份,用 useExisting 代替。

错误处理

调外部接口,出错是家常便饭。网络超时、对方服务挂了、返回 4xx/5xx,都得处理。

用 RxJS 的 catchError 操作符来统一处理:

import { catchError, firstValueFrom } from 'rxjs';
import { AxiosError } from 'axios';
import { Logger } from '@nestjs/common';

@Injectable()
export class CatsService {
  private readonly logger = new Logger(CatsService.name);

  constructor(private readonly httpService: HttpService) {}

  async findAll(): Promise<any[]> {
    const { data } = await firstValueFrom(
      this.httpService.get<any[]>('http://localhost:3000/cats').pipe(
        catchError((error: AxiosError) => {
          this.logger.error(`请求失败: ${error.message}`);
          throw new ServiceUnavailableException('外部服务不可用');
        }),
      ),
    );
    return data;
  }
}
Tip

很多人忘记加错误处理,结果请求失败时 Observable 直接报错,整个请求链就断了。养成习惯,catchError 永远别落下。

直接访问 Axios 实例

如果你觉得 HttpService 的封装不够用,想直接操作底层的 Axios 实例,可以通过 axiosRef 拿到:

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

  async findAll(): Promise<AxiosResponse<any[]>> {
    // 直接用 axiosRef,返回的就是 Promise 了
    return this.httpService.axiosRef.get('http://localhost:3000/cats');
  }
}

axiosRef 给你的是原始的 Axios 实例,所有方法返回的都是 Promise,不走 Observable 那套。

Note

axiosRef 会绕过 NestJS 的 Observable 封装。好处是写法更简单,坏处是失去了 RxJS 操作符的能力。一般场景下建议优先用 HttpService 的标准方法。

实际应用模式

封装外部 API 调用

把对外部接口的调用封装成独立服务,让其他服务通过依赖注入使用:

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

  async getWeather(city: string): Promise<WeatherData> {
    const { data } = await firstValueFrom(
      this.httpService.get<WeatherData>(
        `https://api.weather.com/v1/current`,
        { params: { city } },
      ),
    );
    return data;
  }
}

这样调用方只需要依赖 WeatherService,不用关心底层的 HTTP 细节。

请求重试

网络请求偶尔失败很正常,加个重试能提高稳定性:

import { retry, firstValueFrom } from 'rxjs';

async getData(): Promise<any> {
  const { data } = await firstValueFrom(
    this.httpService.get('https://api.example.com/data').pipe(
      retry(3), // 失败后最多重试 3 次
    ),
  );
  return data;
}

这就是 Observable 的优势了——加个 retry 操作符就搞定,用 Promise 的话你得自己写循环。

小结

  • HttpModule 封装了 Axios,返回 Observable
  • firstValueFrom 可以转成 Promise
  • register 传静态配置,registerAsync 传动态配置
  • 别忘了加 catchError 处理错误
  • 想直接用 Axios 原始能力,通过 axiosRef 访问