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

如何在NestJS与TypeScript中使用File作为数据类型?

解决NestJS GraphQL中无法声明File类型的问题

在NestJS GraphQL场景下,DTO中无法直接使用原生File类型会触发Undefined type error,以下是几种可行的解决方案:

方案一:使用GraphQL Upload scalar处理文件

这是GraphQL官方推荐的文件上传方案,需要配置对应的标量类型:

  1. 安装依赖
    确保安装兼容版本的包:
npm install graphql-upload @nestjs/graphql graphql

(注:NestJS 10+建议搭配graphql-upload@^16.0.2使用)

  1. 注册Upload标量
    在GraphQL模块中注册Upload标量类型:
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { GraphQLUpload } from 'graphql-upload';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: true,
      resolvers: { Upload: GraphQLUpload }, // 注册Upload标量
    }),
  ],
})
export class AppModule {}
  1. 在DTO中使用FileUpload类型
    创建输入DTO并显式指定Upload类型:
import { InputType, Field } from '@nestjs/graphql';
import { FileUpload } from 'graphql-upload';

@InputType()
export class CreateItemInput {
  @Field(() => GraphQLUpload)
  image: FileUpload;

  // 其他业务字段...
}
  1. 在Resolver中处理文件
    接收并处理上传的文件流:
import { Resolver, Mutation, Args } from '@nestjs/graphql';
import { FileUpload, createWriteStream } from 'graphql-upload';
import { promisify } from 'util';
import { pipeline } from 'stream';

const pump = promisify(pipeline);

@Resolver()
export class ItemResolver {
  @Mutation(() => Boolean)
  async uploadImage(@Args('input') input: CreateItemInput) {
    const { createReadStream, filename } = await input.image;
    // 将文件保存到本地或云存储
    await pump(createReadStream(), createWriteStream(`./uploads/${filename}`));
    return true;
  }
}

方案二:通过Base64编码传递文件

如果不想配置GraphQL Upload,可以将文件转为Base64字符串传递,后端用字符串类型接收:

  1. 前端转换文件为Base64
    在React端将File对象转为Base64字符串:
const fileToBase64 = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
};

// 调用示例
const base64Image = await fileToBase64(selectedFile);
  1. 后端DTO接收字符串类型
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateItemInput {
  @Field()
  image: string; // 接收Base64格式的字符串

  // 其他业务字段...
}
  1. 后端解析Base64为文件
    在Resolver中将Base64字符串转为文件:
import { Resolver, Mutation, Args } from '@nestjs/graphql';
import { writeFile } from 'fs/promises';

@Resolver()
export class ItemResolver {
  @Mutation(() => Boolean)
  async uploadImage(@Args('input') input: CreateItemInput) {
    // 移除Base64前缀(如data:image/png;base64,)
    const base64Data = input.image.replace(/^data:image\/\w+;base64,/, '');
    const buffer = Buffer.from(base64Data, 'base64');
    await writeFile('./uploads/image.png', buffer);
    return true;
  }
}

方案三:改用REST接口处理文件上传

如果GraphQL不是必须的,直接用NestJS的Multer中间件处理REST接口的文件上传:

  1. 配置Multer模块
import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';

@Module({
  imports: [
    MulterModule.register({
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          cb(null, `${uniqueSuffix}${extname(file.originalname)}`);
        },
      }),
    }),
  ],
})
export class AppModule {}
  1. 创建REST上传接口
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('image'))
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
    // 返回文件访问路径或URL
    return { url: `/uploads/${file.filename}` };
  }
}

前端调用该REST接口获取文件URL后,再将URL传入GraphQL接口使用即可。

内容的提问来源于stack exchange,提问作者Jawad Ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:11:39