nestjs上传文件multer详解

前言

最近在开发一个商城项目, 后端使用的nestjs+mongodb, 上传文件在一个系统里肯定是必不可少的。multer是官方推荐的上传文件方案, 虽然官方文档写的很详细, 但实战中还是遇到了一些坑, 在此码文记录一下, 希望对你快速上手有所帮助。

memory or disk?

multer假如没有任何配置默认就是储存在内存中, 上传文件的数据结构大概是这样

js 复制代码
{
  fieldname: 'file',
  originalname: 'unnamed.png',
  encoding: '7bit',
  mimetype: 'image/png',
  buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 c0 00 00 00 c0 08 03 00 00 00 65 02 9c 35 00 00 00 03 73 42 49 54 08 08 08 db e1 4f e0 00 00 ... 10782 more bytes>,
  size: 10832
}

一般来说, 不涉及到文件转换的逻辑不会用到这个, 硬盘存储应该是我们更常见的需求, 我们需要额外配置一些选项

js 复制代码
import { MulterModule } from '@nestjs/platform-express';

MulterModule.register({
  dest: './public', // 配置文件硬盘存储的地址, destination 指向项目根目录
});

硬盘存储上传文件数据格式这样的

js 复制代码
{
  fieldname: 'file', 
  originalname: 'unnamed.png',             //原文件名 
  encoding: '7bit',                        
  mimetype: 'image/png',
  destination: './public',                 //文件的储存的文件夹位置
  filename: '1704774383763-unnamed.png',   //为了不重名, 上传后的文件名中加了一个时间戳
  path: 'public/1704774383763-unnamed.png', 
  size: 10832                              //文件大小
}

硬盘存储的配置(三种维度)

  1. 全局配置: 假如项目比较小, 所有文件只需要塞一个文件夹里即可的话, 全局无疑是最佳选择
js 复制代码
import { Module, Global } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { diskStorage } from 'multer';
import { MulterModule } from '@nestjs/platform-express';  // nest底层就是express, 而express又内置multer, 所以不需要再安装, 只需要安装一下类型即可npm i -D @types/multer

@Global()  // 全局导出的decoration
@Module({
  imports: [
    MulterModule.register({
      storage: diskStorage({
        destination: './public',
        filename: (req, file, cb) => {
          return cb(null, `${Date.now()}-${file.originalname}`);
        },
      }),
    }),
  ],
  controllers: [AppController],
  providers: [],
  exports: [MulterModule],  // 导出MulterModule
})
export class AppModule {}

使用了@global就不需要一个个在子module中去import MulterModule这个模块了

  1. 模块配置: 子模块导入的代码基本和上述一致, 针对于每个模块存放的文件位置不一致, 可以每个module各自配置, 而且不需要exports

  2. 拦截器配置: 当然还有一种情况, 就是在同一个模块中,不同接口的存储位置也是不同的, 所以multer颗粒度可以精确到每个接口

js 复制代码
import { diskStorage } from 'multer';
import { FileInterceptor } from '@nestjs/platform-express';

@UseInterceptors(FileInterceptor('file', {
  storage: diskStorage({
    destination: './another_uploads',
    filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`);
    },
  }),
}))
uploadFile(@UploadedFile() file) {
  console.log(file);
}

nestjs 静态文件服务

上述我们讲了nestjs上传文件的代码, 上传之后必然是需要访问的, 这就涉及到了nestjs的静态文件服务, 也很简单,首先安装包

js 复制代码
npm install --save @nestjs/serve-static

然后在app.module.ts中导入即可

js 复制代码
import { Module, Global } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { ServeStaticModule } from '@nestjs/serve-static';
import { diskStorage } from 'multer';
import { join } from 'path';

@Global()
@Module({
  imports: [
    MulterModule.register({
      storage: diskStorage({
        destination: './public',
        filename: (req, file, cb) => {
          return cb(null, `${Date.now()}-${file.originalname}`);
        },
      }),
    }),
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
    }),
  ],
  controllers: [AppController],
  providers: [],
  exports: [MulterModule],
})
export class AppModule {}

这样你上传的文件, 就可以通过your.domain.com/filename.su... 访问了

后序

最近打算做一个鞋类商城全栈项目,移动端flutter + react-native,管理后端arco + vue3 + mongo + nodejs, 感兴趣的朋友可以关注我。

相关推荐
222you9 分钟前
Claude Code接入DeepSeek-v4模型
java·服务器·前端
轻口味23 分钟前
AI 时代全栈开发破局:TypeScript 生态实战,从入门到部署一站式通关
前端·mongodb·docker·ai·typescript·react·next.js
ZC跨境爬虫32 分钟前
跟着MDN学HTML_day_45:(EventTarget接口)
前端·javascript·ui·html·媒体
漂移的电子1 小时前
【el-tree】外层多选,某个属性内层单选
前端·javascript·vue.js
BJ-Giser1 小时前
Cesium 体积光阴影率分析和阴影体渲染效果
前端·可视化·cesium
幽络源小助理1 小时前
YK一点资讯Zblog主题源码, 游戏攻略新闻资讯模板
前端·php源码
RPGMZ1 小时前
RPGMZ NPC头顶自动显示一段消息
前端·游戏引擎·rpgmz·rpgmakermz
DFT计算杂谈1 小时前
AMSET 设置多核并行计算
java·前端·css·html·css3
花椒技术1 小时前
AI 协同开发落地复盘:1 小时生成首版后,为什么 Review 和修正又花了 2-3 天
前端·人工智能·架构
万少2 小时前
万少用9个AI工具,帮朋友完成了一个"不可能"的项目
前端