HTTP模块
本教程共 47 篇 · 第 33 篇 · 更新于 2026-08-09 · 约 8 分钟阅读
本节目标:学会用 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访问