You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nest.js使用Axios发送POST参数请求报循环结构转JSON错误解决方法

问题根因

TypeError: Converting circular structure to JSON 报错的核心触发逻辑是:执行JSON序列化操作时,待序列化的对象存在循环引用(即对象属性直接/间接指向自身)。在NestJS + Axios的场景下,90%以上的该报错来自以下三种错误写法:

  • 路由层直接将@Req()拿到的完整请求对象传给Service层,该对象内置了request/response/socket等大量带循环引用的框架属性
  • Service层调用Axios拿到响应后,直接将完整的Axios Response对象作为接口返回值,该对象自带config/request属性,和自身形成循环引用,NestJS序列化返回值时直接抛错
  • 参数拼接过程中误将框架上下文对象混入业务参数,传入序列化逻辑触发报错
正确实现方案

首先确认项目已安装@nestjs/axios依赖,并在业务模块中导入HttpModule:

// create.module.ts
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { CreateController } from './create.controller';
import { CreateService } from './create.service';

@Module({
  imports: [HttpModule.register({ timeout: 5000 })],
  controllers: [CreateController],
  providers: [CreateService],
})
export class CreateModule {}

1. create.validator.ts 参数校验层

从入口拦截非预期字段,确保传入Service的是纯业务数据,避免框架属性混入:

import { IsNumber, IsString, IsArray, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

// 按实际排班对象字段调整校验规则
class RosterItemDto {
  @IsNumber()
  staffId: number;

  @IsString()
  shift: string;
}

export class CreateReqDto {
  @IsNumber()
  id: number;

  @IsString()
  date: string;

  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => RosterItemDto)
  roster: RosterItemDto[];
}

2. create.controller.ts 路由层

只传递校验通过的纯请求体给Service,禁止传入完整的Req/Res框架对象:

import { Controller, Post, Body } from '@nestjs/common';
import { CreateService } from './create.service';
import { CreateReqDto } from './create.validator';

@Controller('api')
export class CreateController {
  constructor(private readonly createService: CreateService) {}

  @Post('create')
  async create(@Body() reqBody: CreateReqDto) {
    return this.createService.submitToTarget(reqBody);
  }
}

3. create.service.ts 业务逻辑层

核心注意两点:一是拼接参数时只处理纯业务字段,二是Axios请求结果只取data属性返回,禁止直接返回完整响应对象:

import { Injectable, BadRequestException } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
import { URLSearchParams } from 'url';
import { CreateReqDto } from './create.validator';

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

  async submitToTarget(params: CreateReqDto) {
    const targetBaseUrl = 'https://create.com/api/index.php';
    try {
      // 拼接URL参数逻辑,适配数组类型的roster字段
      const searchParams = new URLSearchParams();
      Object.entries(params).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach(item => searchParams.append(`${key}[]`, JSON.stringify(item)));
        } else {
          searchParams.append(key, String(value));
        }
      });
      const fullTargetUrl = `${targetBaseUrl}?${searchParams.toString()}`;

      // 发起POST请求,如果需要传JSON格式body就把params放到post第二个参数位置
      const { data } = await firstValueFrom(
        this.httpService.post(fullTargetUrl)
      );

      return {
        code: 200,
        msg: '请求成功',
        result: data
      };
    } catch (err) {
      throw new BadRequestException(`目标接口请求失败: ${err.message}`);
    }
  }
}
避坑提示
  • 禁止在参数、返回值中传入NestJS的Request/Response/ExecutionContext、Axios完整响应/错误对象,这类对象均存在循环引用,序列化时必然触发报错
  • 若使用JSON.stringify()手动处理参数,提前确认传入对象仅包含业务字段,无挂载的框架属性
  • 数组类型参数拼接时不要直接做强制类型转换,按后端要求的数组传参格式处理即可

内容的提问来源于stack exchange,提问作者Rzj EM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:33:30