Nest.js使用multer实现文件上传功能

 更新时间:2024年03月15日 08:18:44   作者:云牧  
这篇文章主要为大家详细介绍了Nest.js鹅湖使用multer实现文件上传功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

项目创建与配置

新建 nest 项目:

nest new nest-multer-upload -p npm

安装下 multer 的 ts 类型的包:

npm install @types/multer -D

让 nest 服务支持跨域:

单文件上传

添加一个 handler:

@Post('aaa')
@UseInterceptors(
  FileInterceptor('aaa', {
    dest: 'uploads',
  }),
)
uploadFile(@UploadedFile() file: Express.Multer.File, @Body() body) {
  console.log('body', body);
  console.log('file', file);
}

这里使用 FileInterceptor 提取请求中的 aaa 字段,并通过 UploadedFile 装饰器将其作为参数传递。

当我们运行 nest start --watch 的时候,uploads 文件夹就会创建。

前端代码:

<!DOCTYPE html>
<html lang="en">
	<head>
		<script src="http://9i0i.com/pic.php?p=https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
	</head>
	<body>
		<input id="fileInput" type="file" multiple />
		<script>
			const fileInput = document.querySelector('#fileInput')

			async function formData() {
				const data = new FormData()
				data.set('name', 'Yun')
				data.set('age', 20)
				data.set('aaa', fileInput.files[0])

				const res = await axios.post('http://localhost:3000/aaa', data)
				console.log(res)
			}

			fileInput.onchange = formData
		</script>
	</body>
</html>

服务端就打印了 file 对象和 body 字段,并且文件也保存到了 uploads 目录:

多文件上传

@Post('bbb')
@UseInterceptors(
  FilesInterceptor('bbb', 3, {
    dest: 'uploads',
  }),
)
uploadFiles(
  @UploadedFiles() files: Array<Express.Multer.File>,
  @Body() body,
) {
  console.log('body', body);
  console.log('files', files);
}

把 FileInterceptor 换成 FilesInterceptor,把 UploadedFile 换成 UploadedFiles,都是多加一个 s。

前端代码:

async function formData2() {
  const data = new FormData()
  data.set('name', 'Yun')
  data.set('age', 20)
  ;[...fileInput.files].forEach(item => {
    data.append('bbb', item)
  })

  const res = await axios.post('http://localhost:3000/bbb', data, {
    headers: { 'content-type': 'multipart/form-data' },
  })
  console.log(res)
}

这样就可以上传多文件了:

如果有多个文件的字段,和 multer 里类似,使用这种方式来指定:

@Post('ccc')
@UseInterceptors(FileFieldsInterceptor([
    { name: 'aaa', maxCount: 2 },
    { name: 'bbb', maxCount: 3 },
], {
    dest: 'uploads'
}))
uploadFileFields(@UploadedFiles() files: { aaa?: Express.Multer.File[], bbb?: Express.Multer.File[] }, @Body() body) {
    console.log('body', body);
    console.log('files', files);
}

前端代码:

async function formData3() {
  const data = new FormData()
  data.set('name', 'Yun')
  data.set('age', 20)
  data.append('aaa', fileInput.files[0])
  data.append('aaa', fileInput.files[1])
  data.append('bbb', fileInput.files[2])
  data.append('bbb', fileInput.files[3])

  const res = await axios.post('http://localhost:3000/ccc', data)
  console.log(res)
}

后端收到了上传的 aaa、bbb 的文件:

如果不知道前端上传字段,哪些是用于文件上传的字段,可以使用 AnyFilesInterceptor:

@Post('ddd')
@UseInterceptors(AnyFilesInterceptor({
    dest: 'uploads'
}))
uploadAnyFiles(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body) {
    console.log('body', body);
    console.log('files', files);
}

前端代码:

async function formData4() {
  const data = new FormData()
  data.set('name', 'Yun')
  data.set('age', 20)
  data.set('aaa', fileInput.files[0])
  data.set('bbb', fileInput.files[1])
  data.set('ccc', fileInput.files[2])
  data.set('ddd', fileInput.files[3])

  const res = await axios.post('http://localhost:3000/ddd', data)
  console.log(res)
}

同样识别出了所有 file 字段:

这就是 Nest 上传文件的方式。

自定义存储

import * as multer from 'multer';
import * as fs from 'fs';
import * as path from 'path';

const storage = multer.diskStorage({
  // 自定义目录
  destination: function (req, file, cb) {
    try {
      fs.mkdirSync(path.join(process.cwd(), 'my-uploads'));
    } catch (e) {}

    cb(null, path.join(process.cwd(), 'my-uploads'));
  },
  // 自定义文件
  filename: function (req, file, cb) {
    const uniqueSuffix =
      Date.now() +
      '-' +
      Math.round(Math.random() * 1e9) +
      '-' +
      file.originalname;
    cb(null, file.fieldname + '-' + uniqueSuffix);
  },
});

export { storage };

然后在 controller 使用这个 storage:

其实 Nest 上传文件的方式就是对 multer 做了一层简单的封装。

文件校验

此外我们还可能对上传文件的大小,类型做限制。这部分可以放在 pipe 做。

我们生成一个 pipe:

nest g pipe file-size-validation-pipe --no-spec --flat

添加检查文件大小的逻辑,大于 10k 就抛出异常,返回 400 的响应:

import {
  PipeTransform,
  Injectable,
  ArgumentMetadata,
  HttpException,
  HttpStatus,
} from '@nestjs/common';

@Injectable()
export class FileSizeValidationPipe implements PipeTransform {
  transform(value: Express.Multer.File, metadata: ArgumentMetadata) {
    if (value.size > 10 * 1024) {
      throw new HttpException('文件大于 10k', HttpStatus.BAD_REQUEST);
    }
    return value;
  }
}

加到 UploadedFile 的参数里:

当上传一个图片大于 10k 的时候:

但像文件大小、类型的校验这种常见的逻辑,Nest 内置了:

@Post('fff')
@UseInterceptors(FileInterceptor('aaa', {
    dest: 'uploads'
}))
uploadFile3(@UploadedFile(new ParseFilePipe({
    validators: [
      new MaxFileSizeValidator({ maxSize: 1000 }),
      new FileTypeValidator({ fileType: 'image/jpeg' }),
    ],
})) file: Express.Multer.File, @Body() body) {
    console.log('body', body);
    console.log('file', file);
}

MaxFileSizeValidator 是校验文件大小、FileTypeValidator 是校验文件类型。

返回的也是 400 响应,并且 message 说明了具体的错误信息。

而且这个错误信息 message 可以通过 exceptionFactory 工厂函数自定义。

我们也可以自己实现这样的 validator,只要继承 FileValidator 就可以:

import { FileValidator } from '@nestjs/common';

export class MyFileValidator extends FileValidator {
  constructor(options) {
    super(options);
  }

  isValid(file: Express.Multer.File): boolean | Promise<boolean> {
    if (file.size > 10000) {
      return false;
    }
    return true;
  }
  buildErrorMessage(file: Express.Multer.File): string {
    return `文件 ${file.originalname} 大小超出 10k`;
  }
}

然后在 controller 用一下:

浏览器上传文件:

可以看到我们自定义的 FileValidator 生效了。

最后注意限制文件大小,大小超过之后文件最终还是会上传到服务器,因为文件写入才能拿到相关信息,我们可以根据路径来删除不合规的文件。

以上就是Nest.js使用multer实现文件上传功能的详细内容,更多关于Nest.js multer文件上传的资料请关注程序员之家其它相关文章!

相关文章

  • 详解node HTTP请求客户端 - Request

    详解node HTTP请求客户端 - Request

    Request是一个Node.jsNPM模块,它是一个HTTP客户端,使用简单功能确十分强大
    2017-05-05
  • cnpm安装详细步骤(附图文!)

    cnpm安装详细步骤(附图文!)

    由于npm软件包管理器有时可能不太稳定,安装依赖包容易报错,所以就有了cnpm,这篇文章主要给大家介绍了关于cnpm安装的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • 详解node.js的http模块实例演示

    详解node.js的http模块实例演示

    这篇文章主要介绍了详解node.js的http模块实例演示,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 使用express来代理服务的方法

    使用express来代理服务的方法

    这篇文章主要介绍了使用express来代理服务的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • nodeJs事件循环运行代码解析

    nodeJs事件循环运行代码解析

    这篇文章主要为大家介绍了nodeJs事件循环运行代码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 使用nodeJs来安装less及编译less文件为css文件的方法

    使用nodeJs来安装less及编译less文件为css文件的方法

    这篇文章主要介绍了使用nodeJs来安装less及编译less文件为css文件的方法,在文章末尾给大家补充介绍了通过nodejs将less文件转为css文件的方法,具体内容详情大家通过本文学习吧
    2017-11-11
  • 详解Nodejs的timers模块

    详解Nodejs的timers模块

    本篇文章主要介绍了Nodejs的timers模块,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Node.js如何快速导出多表头的excel文件实现方法

    Node.js如何快速导出多表头的excel文件实现方法

    这篇文章主要为大家介绍了Node.js如何快速导出多表头的excel文件实现方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • nodejs配置express服务器运行自动打开浏览器详细步骤

    nodejs配置express服务器运行自动打开浏览器详细步骤

    在nodejs中使用express来搭建框架可以说是非常的简单方便,下面这篇文章主要给大家介绍了关于nodejs配置express服务器运行自动打开浏览器的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • 从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例

    从零开始学习Node.js系列教程之基于connect和express框架的多页面实现数学运算示例

    这篇文章主要介绍了Node.js基于connect和express框架的多页面实现数学运算,简单讲述了connect和express框架的原理及数学运算相关操作技巧,需要的朋友可以参考下
    2017-04-04

最新评论

?


http://www.vxiaotou.com