1. 回顾 Express 的 multer
上节我们学了 Express 的 multer:
// Express 写法
app.post('/upload', upload.single('file'), (req, res) => {
req.file; // 文件
req.body; // 其他字段
});
Nest 怎么写?
2. Nest 文件上传 - 三步走
第 1 步:安装类型包
npm install -D @types/multer
第 2 步:写接口
@Post('aaa')
@UseInterceptors(FileInterceptor('aaa', {
dest: 'uploads' // 保存目录
}))
uploadFile(
@UploadedFile() file: Express.Multer.File,
@Body() body
) {
console.log('文件信息:', file);
console.log('其他字段:', body);
}
第 3 步:前端上传
<input type="file" id="fileInput" />
<script>
const fileInput = document.querySelector('#fileInput');
fileInput.onchange = async () => {
const data = new FormData();
data.set('aaa', fileInput.files[0]);
await axios.post('http://localhost:3000/aaa', data);
};
</script>
3. 对比 Express
| Express | Nest | 说明 |
|---|---|---|
upload.single('field') | FileInterceptor('field') | 单文件 |
upload.array('field', n) | FilesInterceptor('field', n) | 多文件 |
upload.fields([...]) | FileFieldsInterceptor([...]) | 多字段 |
upload.any() | AnyFilesInterceptor() | 任意文件 |
req.file | @UploadedFile() | 获取文件 |
req.files | @UploadedFiles() | 获取文件数组 |
req.body | @Body() | 获取其他字段 |
4. 多文件上传
后端
@Post('bbb')
@UseInterceptors(FilesInterceptor('bbb', 3, {
dest: 'uploads'
}))
uploadFiles(
@UploadedFiles() files: Array<Express.Multer.File>,
@Body() body
) {
console.log('文件列表:', files);
}
前端
// 传多个文件
[...fileInput.files].forEach(file => {
data.append('bbb', file);
});
await axios.post('http://localhost:3000/bbb', data);
对比 Element Plus:
<el-upload
action="/api/upload"
:auto-upload="false"
:on-change="handleChange"
multiple
>
</el-upload>
5. 不同字段传不同文件
场景:头像 + 附件分开传
后端
@Post('ccc')
@UseInterceptors(FileFieldsInterceptor([
{ name: 'avatar', maxCount: 1 }, // 头像,最多1个
{ name: 'attachments', maxCount: 3 } // 附件,最多3个
], {
dest: 'uploads'
}))
uploadFileFields(
@UploadedFiles() files: { avatar?: Express.Multer.File[], attachments?: Express.Multer.File[] },
@Body() body
) {
console.log('头像:', files.avatar);
console.log('附件:', files.attachments);
}
前端
const data = new FormData();
data.append('avatar', avatarFile);
data.append('attachments', file1);
data.append('attachments', file2);
await axios.post('http://localhost:3000/ccc', data);
对比 el-upload 多文件上传:
<el-upload
action="/api/upload"
:auto-upload="false"
:file-list="fileList"
>
<el-button>上传头像和附件</el-button>
</el-upload>
6. 任意文件上传
不知道有哪些字段会上传文件?
@Post('ddd')
@UseInterceptors(AnyFilesInterceptor({
dest: 'uploads'
}))
uploadAnyFiles(
@UploadedFiles() files: Array<Express.Multer.File>,
@Body() body
) {
console.log('所有文件:', files);
}
7. 文件信息详解
上传成功后,file 对象包含:
{
fieldname: 'aaa', // 字段名
originalname: '1.png', // 原始文件名
encoding: '7bit', // 编码
mimetype: 'image/png', // MIME 类型
size: 1024, // 文件大小(字节)
destination: 'uploads', // 保存目录
filename: 'xxx.png', // 保存的文件名
path: 'uploads/xxx.png' // 完整路径
}
对比前端的 file 对象:
// 前端 file 对象
{
name: '1.png', // 文件名
size: 1024, // 大小
type: 'image/png', // 类型
lastModified: 1234567890
}
8. 完整流程图
前端 Nest
─── ───
FormData + axios ──────────► @UseInterceptors
│ FileInterceptor
│ │
│ multipart/form-data │
│ │
│ @UploadedFile()
│ ▼
│ 保存到磁盘
│ │
◄────────────────────────────────────┘
响应
9. 总结
| Nest 装饰器 | 对应 Express | 作用 |
|---|---|---|
FileInterceptor | upload.single() | 单文件上传 |
FilesInterceptor | upload.array() | 多文件上传 |
FileFieldsInterceptor | upload.fields() | 多字段多文件 |
AnyFilesInterceptor | upload.any() | 任意文件 |
@UploadedFile() | req.file | 获取单文件 |
@UploadedFiles() | req.files | 获取文件数组 |
@Body() | req.body | 获取其他字段 |
一句话总结:
Nest 文件上传就是包装了 Express multer 的拦截器版本,用
@UseInterceptors+@UploadedFile的方式接收文件,和前端的 el-upload 完美对应。
Express = 手写中间件 Nest = 装饰器 + 拦截器,更优雅!
觉得有帮助,点个赞再走~ 👋