Nestjs项目实战 文件上传功能详解

在Nestjs中实现文件上传功能时遇到了几个问题:

  1. 如何正确配置Multer模块来处理文件上传?官方文档的示例感觉不够详细,比如文件大小限制和类型过滤该怎么设置?

  2. 上传后的文件存储路径应该如何管理?是否建议直接保存到项目目录,还是说要用云存储更合适?

  3. 前端传文件时总是出现400 Bad Request错误,但Postman测试是正常的,这可能是什么原因?需要特别设置请求头吗?

  4. 有没有完整的文件上传示例代码可以参考?包括控制器、服务层和异常处理的最佳实践?

  5. 大文件分片上传在Nestjs中要怎么实现?需要考虑哪些关键点?

3 回复

在NestJS中实现文件上传功能可以借助[@nestjs](/user/nestjs)/common和第三方库如multer。以下是详细步骤:

  1. 安装依赖: 使用npm安装必要的依赖包:

    npm install [@nestjs](/user/nestjs)/platform-express multer
    
  2. 配置Multer: 创建一个Multer存储配置,定义文件的存储路径和命名规则。

    import { diskStorage } from 'multer';
    import { v4 as uuid } from 'uuid';
    
    export const storage = diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
            const ext = file.mimetype.split('/')[1];
            const filename = `${uuid()}.${ext}`;
            cb(null, filename);
        }
    });
    
  3. 创建控制器: 在控制器中使用@UseInterceptors装饰器结合FileInterceptor来处理文件上传。

    import { Controller, Post, UseInterceptors, UploadedFile } from '[@nestjs](/user/nestjs)/common';
    import { FileInterceptor } from '[@nestjs](/user/nestjs)/platform-express';
    import { storage } from './multer.config';
    
    [@Controller](/user/Controller)('upload')
    export class UploadController {
        @Post()
        @UseInterceptors(FileInterceptor('file', { storage }))
        uploadFile(@UploadedFile() file: Express.Multer.File) {
            return { filename: file.filename };
        }
    }
    
  4. 前端请求: 使用HTML表单或Axios发送文件请求。例如:

    <form action="/upload" method="POST" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">Upload</button>
    </form>
    
  5. 运行项目: 启动应用后,即可通过表单或API上传文件。

此方法简单高效,适合中小型项目。若需更复杂的功能(如分片上传),可考虑引入更多高级配置或模块。


在NestJS中实现文件上传功能,可以使用@nestjs/common中的内置模块和第三方库如multer来处理。首先安装依赖:

npm install @nestjs/platform-express multer

创建一个服务用于处理文件上传逻辑。例如,upload.service.ts

import { Injectable } from '@nestjs/common';
import * as fs from 'fs';

@Injectable()
export class UploadService {
  uploadFile(file: Express.Multer.File): string {
    const filePath = `uploads/${file.filename}`;
    fs.renameSync(file.path, filePath);
    return filePath;
  }
}

在控制器中配置Multer中间件,并定义路由:

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { UploadService } from './upload.service';

@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post()
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const ext = file.originalname.split('.').pop();
          cb(null, `${uniqueSuffix}.${ext}`);
        },
      }),
    }),
  )
  async uploadFile(@UploadedFile() file): Promise<string> {
    if (!file) {
      throw new Error('No file uploaded');
    }
    return this.uploadService.uploadFile(file);
  }
}

这样,当用户上传文件时,文件会被存储到./uploads目录下,同时返回文件路径。记得配置uploads目录的读写权限。

NestJS 文件上传功能详解

基础配置

  1. 首先安装所需依赖:
npm install @nestjs/platform-express multer @types/multer
  1. 配置文件上传模块:
// file.module.ts
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, callback) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const ext = extname(file.originalname);
          callback(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
        },
      }),
    }),
  ],
})
export class FileModule {}

控制器实现

// file.controller.ts
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('file')
export class FileController {
  @Post('upload')
  @UseInterceptors(FileInterceptor('file')) // 'file'是前端表单字段名
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    return {
      filename: file.filename,
      originalname: file.originalname,
      size: file.size,
      mimetype: file.mimetype,
      path: file.path,
    };
  }
}

多文件上传

@Post('multiple')
@UseInterceptors(FilesInterceptor('files')) // 多个文件,字段名为files
uploadMultipleFiles(@UploadedFiles() files: Array<Express.Multer.File>) {
  return files.map(file => ({
    filename: file.filename,
    originalname: file.originalname,
  }));
}

文件大小和类型限制

@Post('upload')
@UseInterceptors(FileInterceptor('file', {
  limits: {
    fileSize: 1024 * 1024 * 5, // 5MB限制
  },
  fileFilter: (req, file, callback) => {
    if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
      return callback(new Error('只允许上传图片文件'), false);
    }
    callback(null, true);
  },
}))

实际应用建议

  1. 存储策略:考虑使用云存储服务如AWS S3、阿里云OSS等替代本地存储
  2. 安全考虑
    • 验证文件类型
    • 限制文件大小
    • 重命名上传文件防止路径穿越攻击
  3. 性能优化
    • 对大文件考虑分片上传
    • 提供上传进度反馈

以上是NestJS文件上传的基本实现,可以根据实际需求进行扩展和优化。

回到顶部