使用nestjs和multer上传文件

Vic*_*ens 2 nestjs

由于nestjs是一个快速应用程序,因此可以使用任何库来处理使用嵌套的上传,并且由于它提供了Midlewares,因此也可以使用multer.我的问题是:使用nestjs处理文件上传的最佳方法是什么?

San*_*air 17

一种更简洁的方法是将配置提取到一个单独的文件中,然后在拦截器方法中调用它

import { extname } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';

// Multer configuration
export const multerConfig = {
    dest: process.env.UPLOAD_LOCATION,
};

// Multer upload options
export const multerOptions = {
    // Enable file size limits
    limits: {
        fileSize: +process.env.MAX_FILE_SIZE,
    },
    // Check the mimetypes to allow for upload
    fileFilter: (req: any, file: any, cb: any) => {
        if (file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
            // Allow storage of file
            cb(null, true);
        } else {
            // Reject file
            cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);
        }
    },
    // Storage properties
    storage: diskStorage({
        // Destination storage path details
        destination: (req: any, file: any, cb: any) => {
            const uploadPath = multerConfig.dest;
            // Create folder if doesn't exist
            if (!existsSync(uploadPath)) {
                mkdirSync(uploadPath);
            }
            cb(null, uploadPath);
        },
        // File modification details
        filename: (req: any, file: any, cb: any) => {
            // Calling the callback passing the random name generated with the original extension name
            cb(null, `${uuid()}${extname(file.originalname)}`);
        },
    }),
};
Run Code Online (Sandbox Code Playgroud)

然后像这样在拦截器下调用它

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'
import { diskStorage } from 'multer'
import { extname } from 'path'
import { multerOptions } from 'src/config/multer.config';
...

@Post('/action/upload')
@UseInterceptors(FileInterceptor('file', multerOptions))
async upload( @UploadedFile() file) {
  console.log(file)
}
Run Code Online (Sandbox Code Playgroud)

  • @DucTrungMai 确保在应用程序启动之前加载 env 文件。要检查这一点,请在 `main.ts` 文件的开头添加此导入 `import * as dotenv from 'dotenv';` 这可确保在加载应用程序上下文之前环境可供使用。 (2认同)

Vic*_*ens 13

正如@Kamyl在问题https://github.com/nestjs/nest/issues/262上所知,因为v4.6.0可以使用公共文件拦截器使用multer上传文件到nestjs.

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'

... 

@UseInterceptors(FileInterceptor('file'))
async upload( @UploadedFile() file) {
  console.log(file)
}
Run Code Online (Sandbox Code Playgroud)

这样变量file就会有一个buffer


使用Multer选项

它还需要字段名称作为第一个参数,然后是具有Multer选项的数组

import { ... , UseInterceptors, FileInterceptor, UploadedFile } from '@nestjs/common'
import { diskStorage } from 'multer'
import { extname } from 'path'

...

@UseInterceptors(FileInterceptor('file', {
  storage: diskStorage({
    destination: './uploads'
    , filename: (req, file, cb) => {
      // Generating a 32 random chars long string
      const randomName = Array(32).fill(null).map(() => (Math.round(Math.random() * 16)).toString(16)).join('')
      //Calling the callback passing the random name generated with the original extension name
      cb(null, `${randomName}${extname(file.originalname)}`)
    }
  })
}))
async upload( @UploadedFile() file) {
  console.log(file)
}
Run Code Online (Sandbox Code Playgroud)

这样变量file就会有一个filename,destinationpath.

destination从PARAM diskStorage也可以是一个函数,用参数和期望的回调一样filename.通过传递diskStorage文件将自动保存到目的地通知给出的文件名.

通过使用@UploadedFilesFilesInterceptor(复数)也可以处理多个文件


Nec*_*shi 5

使用 Multer 选项的最干净的实现

谢谢@VictorIvens 提供的最佳答案。

但是,我在代码中发现了以下问题

  • 调用的导入FileInterceptor@nestjs/common最新版本的 NestJS 包中不存在。
  • 代码在我看来有点太杂乱了。

所以,为了简化事情,我想出了以下解决方案。

存储配置文件

export const storage = diskStorage({
  destination: "./uploads",
  filename: (req, file, callback) => {
    callback(null, generateFilename(file));
  }
});

function generateFilename(file) {
  return `${Date.now()}.${extname(file.originalname)}`;
}

Run Code Online (Sandbox Code Playgroud)

your-controller.controller.ts

import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFile
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";

import { diskStorage } from "multer";
import { extname } from "path";
import { storage } from "./storage.config"


@Controller()
export class YourController {
  @Post("upload") // API path
  @UseInterceptors(
    FileInterceptor(
      "file", // name of the field being passed
      { storage }
    )
  )
  async upload(@UploadedFile() file) {
    return file;
  }
}
Run Code Online (Sandbox Code Playgroud)