Nest.js使用multer實現(xiàn)文件上傳功能
項目創(chuàng)建與配置
新建 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 裝飾器將其作為參數(shù)傳遞。
當我們運行 nest start --watch
的時候,uploads 文件夾就會創(chuàng)建。
前端代碼:
<!DOCTYPE html> <html lang="en"> <head> <script src="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 的參數(shù)里:
當上傳一個圖片大于 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 工廠函數(shù)自定義。
我們也可以自己實現(xiàn)這樣的 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 生效了。
最后注意限制文件大小,大小超過之后文件最終還是會上傳到服務器,因為文件寫入才能拿到相關信息,我們可以根據(jù)路徑來刪除不合規(guī)的文件。
以上就是Nest.js使用multer實現(xiàn)文件上傳功能的詳細內容,更多關于Nest.js multer文件上傳的資料請關注腳本之家其它相關文章!
相關文章
Node.js中child_process實現(xiàn)多進程
這篇文章主要介紹了Node.js中child_process實現(xiàn)多進程,需要的朋友可以參考下2015-02-02node.js中的http.response.writeHead方法使用說明
這篇文章主要介紹了node.js中的http.response.writeHead方法使用說明,本文介紹了http.response.writeHead的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12詳解NodeJS框架express的路徑映射(路由)功能及控制
這篇文章主要介紹了詳解NodeJS框架express的路徑映射(路由)功能及控制,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03[將免費進行到底]在Amazon的一年免費服務器上安裝Node.JS, NPM和OurJS博客
此文是介紹如何在Amazon的一年免費計劃上安裝Node.JS, NPM還有搭建OurJS博客系統(tǒng)。,需要的朋友可以參考下2014-08-08nodejs連接ftp上傳下載實現(xiàn)方法詳解【附:踩坑記錄】
這篇文章主要介紹了nodejs連接ftp上傳下載實現(xiàn)方法,結合實例形式詳細分析了node.js使用ftp模塊實現(xiàn)針對ftp上傳、下載相關操作的方法,并附帶記錄了傳輸速度慢的解決方法,需要的朋友可以參考下2023-04-04