Express中最常使用的form解析中間件就是body-parser了,可是它明確表示不會支持multipart/form-data
類型的表單.javascript
因此在body-parser官方文檔中提供了以下的幾個支持multipart/form-data
類型的中間件的連接,或者只支持multipart/form-data
解析的中間件連接.html
名稱&地址 | 周下載量 | stars |
---|---|---|
busboy | 426,278 | 1448 |
multipart | 240,921 | 993 |
formidable | 1,390,361 | 4735 |
multer | 284,926 | 5860 |
統計截止到2018年12月26日java
multer依賴busboy因此因此busboy的實際直接下載數量應該要減小28萬😂.git
multipart/form-data
類型的表單?最直觀的解釋就是支持上傳文件的form表單,若是不使用JavaScript中建立的話,顯式的html聲明以下:github
<form action="/profile" method="post" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit" value="submit"> </form>
上例子中的<input type="file" name="file" >
在頁面中的顯示就是爲一個按鈕點擊後能夠進行文件選擇.express
其次input能夠添加multiple="multiple"
屬性,這個時候打開的文件選擇框會容許多選文件.npm
總結一下有以下幾種關係:json
順便說一句multer有中文文檔.windows
enctype="multipart/form-data"
表單.multer會將上傳的信息以及內容掛載到request對象上後端
const express = require('express'), multer = require('multer'), app = express();
const upload = multer({dest:'/uploads'});
注意:dest參數指定了文件輸出的位置,能夠詳細指定文件輸出以及儲存後面會講.
app.get('/',(request,response)=>{ console.log('get.request.body',request.body); console.log('get.request.file',request.file); console.log('get.request.files',request.files); response.send('<form action="/" enctype="multipart/form-data" method="post">'+ '<input type="text" name="title"><br>'+ '<input type="file" name="upload" multiple="multiple"><br>'+ '<input type="submit" value="Upload">'+ '</form>') }); app.post('/',upload.single('upload'),(request,response)=>{ console.log('post.request.body',request.body); console.log('post.request.file',request.file); console.log('post.request.files',request.files); response.redirect('/'); }); app.listen(8888,()=>{ console.log('express正在監聽8888端口'); });
這個例子中咱們監聽了根路徑,分別處理兩種不一樣的請求方式,針對get咱們響應表單,針對post咱們接受上傳的內容.
注意:upload.single('upload')
意思是告訴multer只接收name是upload的單個文件.
注意:這個例子中input
是能夠進行多選的,也就是說後端指定了文件數量爲1可是頁面依然上傳了多個,這個時候multer會報錯.
注意:dest指定的路徑爲upload/
會將文件保存到根路徑下的upload文件夾中,對於windows系統來講是在運行這個應用對應的盤符下例如F:\uploads\
這個例子中我填寫了一個文本內容,同時上傳了一個文件,輸出結果以下:
post.request.body { title: 'hello world' } post.request.file { fieldname: 'upload', originalname: '硬盤壞道掃描及修復工具Victoria.7z', encoding: '7bit', mimetype: 'application/octet-stream', destination: '/uploads', filename: '6bdfc0df998d72e6232d60f790f47ef8', path: '\\uploads\\6bdfc0df998d72e6232d60f790f47ef8', size: 1033375 }
const express = require('express'), multer = require('multer'), app = express(); const upload = multer({dest:'/uploads'}); app.get('/',(request,response)=>{ console.log('get.request.body',request.body); console.log('get.request.file',request.file); console.log('get.request.files',request.files); response.send('<form action="/" enctype="multipart/form-data" method="post">'+ '<input type="text" name="title"><br>'+ '<input type="file" name="upload"><br>'+ // 此處有兩個相同name的input '<input type="file" name="upload"><br>'+ '<input type="submit" value="Upload">'+ '</form>') }); app.post('/',upload.array('upload'),(request,response)=>{ // 注意此處使用的中間件和上例中不一樣 console.log('post.request.body',request.body); console.log('post.request.file',request.file); console.log('post.request.files',request.files); response.redirect('/'); }); app.listen(8888,()=>{ console.log('express正在監聽8888端口'); });
在這個例子的表單中有兩個同名的name都是文件類型,此次使用array的方式來進行接受,控制檯輸出內容以下:
post.request.body { title: 'hello world' } post.request.file undefined post.request.files [ { fieldname: 'upload', originalname: '硬盤壞道掃描及修復工具Victoria.7z', encoding: '7bit', mimetype: 'application/octet-stream', destination: '/uploads', filename: '71ed2ac4299d43a30f5c13892f33e51b', path: '\\uploads\\71ed2ac4299d43a30f5c13892f33e51b', size: 1033375 }, { fieldname: 'upload', originalname: '新建文本文檔.txt', encoding: '7bit', mimetype: 'text/plain', destination: '/uploads', filename: '190bde8fcdd08d57648ffb243607ed9d', path: '\\uploads\\190bde8fcdd08d57648ffb243607ed9d', size: 218 } ]
在上面的例子中刪除掉一個input,將剩餘的input添加multiple
屬性用於多選,頁面中在選擇文件框中選擇多個文件也是能夠順利經過.
除了上方提到的multer.single
方法外還有其餘的幾種方法.
req.files
實際上它們均可以視爲fields方法的包裝,源碼以下:
Multer.prototype.single = function (name) { return this._makeMiddleware([{ name: name, maxCount: 1 }], 'VALUE') } Multer.prototype.array = function (name, maxCount) { return this._makeMiddleware([{ name: name, maxCount: maxCount }], 'ARRAY') } Multer.prototype.fields = function (fields) { return this._makeMiddleware(fields, 'OBJECT') } Multer.prototype.none = function () { return this._makeMiddleware([], 'NONE') } Multer.prototype.any = function () { function setup () { return { limits: this.limits, preservePath: this.preservePath, storage: this.storage, fileFilter: this.fileFilter, fileStrategy: 'ARRAY' } } return makeMiddleware(setup.bind(this)) }
來自中文文檔:
multer(opts)
Multer 接受一個 options 對象,其中最基本的是 dest
屬性,這將告訴 Multer 將上傳文件保存在哪。若是你省略 options 對象,這些文件將保存在內存中,永遠不會寫入磁盤。
爲了不命名衝突,Multer 會修改上傳的文件名。這個重命名功能能夠根據您的須要定製。
如下是能夠傳遞給 Multer 的選項。
Key | Description |
---|---|
dest or storage |
在哪裏存儲文件 |
fileFilter |
文件過濾器,控制哪些文件能夠被接受 |
limits |
限制上傳的數據 |
preservePath |
保存包含文件名的完整文件路徑 |
fileFilter
設置一個函數來控制什麼文件能夠上傳以及什麼文件應該跳過,這個函數應該看起來像這樣:
function fileFilter (req, file, cb) { // 這個函數應該調用 `cb` 用boolean值來 // 指示是否應接受該文件 // 拒絕這個文件,使用`false`,像這樣: cb(null, false) // 接受這個文件,使用`true`,像這樣: cb(null, true) // 若是有問題,你能夠老是這樣發送一個錯誤: cb(new Error('I don\'t have a clue!')) }
當遇到一個錯誤,multer 將會把錯誤發送給 express。你可使用一個比較好的錯誤展現頁 (express標準方式)。
若是你想捕捉 multer 發出的錯誤,你能夠本身調用中間件程序。若是你想捕捉 Multer 錯誤,你可使用 multer
對象下的 MulterError
類 (即 err instanceof multer.MulterError
)。
var multer = require('multer') var upload = multer().single('avatar') app.post('/profile', function (req, res) { upload(req, res, function (err) { if (err instanceof multer.MulterError) { // 發生錯誤 } else if (err) { // 發生錯誤 } // 一切都好 }) })
DiskStorage
)磁盤存儲引擎可讓你控制文件的存儲。
var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, '/tmp/my-uploads') }, filename: function (req, file, cb) { cb(null, file.fieldname + '-' + Date.now()) } }) var upload = multer({ storage: storage })
有兩個選項可用,destination
和 filename
。他們都是用來肯定文件存儲位置的函數。
destination
是用來肯定上傳的文件應該存儲在哪一個文件夾中。也能夠提供一個 string
(例如 '/tmp/uploads'
)。若是沒有設置 destination
,則使用操做系統默認的臨時文件夾。
注意: 若是你提供的 destination
是一個函數,你須要負責建立文件夾。當提供一個字符串,multer 將確保這個文件夾是你建立的。
filename
用於肯定文件夾中的文件名的肯定。 若是沒有設置 filename
,每一個文件將設置爲一個隨機文件名,而且是沒有擴展名的。
注意: Multer 不會爲你添加任何擴展名,你的程序應該返回一個完整的文件名。
每一個函數都傳遞了請求對象 (req
) 和一些關於這個文件的信息 (file
),有助於你的決定。
注意 req.body
可能尚未徹底填充,這取決於向客戶端發送字段和文件到服務器的順序。
MemoryStorage
)內存存儲引擎將文件存儲在內存中的 Buffer
對象,它沒有任何選項。
var storage = multer.memoryStorage() var upload = multer({ storage: storage })
當使用內存存儲引擎,文件信息將包含一個 buffer
字段,裏面包含了整個文件數據。
警告: 當你使用內存存儲,上傳很是大的文件,或者很是多的小文件,會致使你的應用程序內存溢出。
const express = require('express'), multer = require('multer'), app = express(); const storage = multer.diskStorage({ destination:__dirname, // 保存到當前目錄 filename(request,file,callback){ console.log('filename:',file); callback(null,'newfilename');// 修改上傳的文件名稱 } }); const upload = multer({ dest:'/uploads', fileFilter(request,file,cb){ console.log('fileFilter:',file); cb(null,true); }, limits:{ fileSize:100000 // 限制上傳文件大小爲100000字節 }, storage // 使用默認的儲存器 });
最後觸發的順序爲: