Nodejs學習筆記(八)—Node.js + Express 實現上傳文件功能(felixge/node-formidable)
前言
前面講了一個構建網站的示例,這次在此基礎上再說說web的常規功能----文件上傳,示例以一個上傳圖片的功能為例子
上傳功能命名用formidable實現,示例很簡單!
PS:最近比較忙,距上一次更新已經比較久了^_^!
formidable簡介
nodejs原生實現上傳還是比較麻煩,有興趣的自已去參考一下網上有網友寫的代碼
這裏選擇了formidable,也是github上同類功能模塊人氣比較高的
https://github.com/felixge/node-formidable
https://www.npmjs.org/package/formidable
優點:上傳速度比較可觀,占用內存也比較低,簡單易用...
創建項目安裝formidable
1.創建項目sampleUpload
cd 工作目錄
express -e sampleUpload
2.修改package.json文件,添加formidable依賴項
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "express": "~4.0.0", "static-favicon": "~1.0.0", "morgan": "~1.0.0", "cookie-parser": "~1.0.1", "body-parser": "~1.0.0", "debug": "~0.7.4", "ejs": "~0.8.5", "formidable" : "latest" } }
3.安裝依賴項
cd sampleUpload && npm install
安裝成功,一切準備就緒,開始完成這個功能!
實現上傳功能
1.index.ejs文件中構建表單並實現前端驗證(樣式使用和https://www.cnblogs.com/flyingeagle/p/9192962.html一致)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><%= title %></title> <link rel="stylesheet" type="text/css" href="/stylesheets/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="/stylesheets/signin.css" /> </head> <body> <div id="container" class="container"> <% if (locals.success) { %> <div id="alt_sucess" class="alert alert-success"> <%- success %> </div> <% } %> <% if (locals.error) { %> <div id="alt_warning" class="alert alert-warning"> <%= error %> </div> <% } %> <form class="form-signin" role="form" method="post" enctype=‘multipart/form-data‘> <h2 class="form-signin-heading">上傳文件</h2> <input id="fulAvatar" name="fulAvatar" type="file" class="form-control" /> <br/> <button id="btnSub" class="btn btn-lg btn-primary" type="submit">上 傳</button> </form> </div> </body> </html> <script src="/javascripts/jquery-1.11.1.min.js" type="text/javascript"></script> <script type="text/javascript"> String.prototype.format = function (args) { var result = this; if (arguments.length > 0) { if (arguments.length == 1 && typeof (args) == "object") { for (var key in args) { if (args[key] != undefined) { var reg = new RegExp("({" + key + "})", "g"); result = result.replace(reg, args[key]); } } } else { for (var i = 0; i < arguments.length; i++) { if (arguments[i] != undefined) { var reg = new RegExp("({)" + i + "(})", "g"); result = result.replace(reg, arguments[i]); } } } } return result; } $(function(){ $(‘#btnSub‘).on(‘click‘,function(){ var fulAvatarVal = $(‘#fulAvatar‘).val(), errorTip = ‘<div id="errorTip" class="alert alert-warning">{0}</div> ‘; $("#errorTip,#alt_warning").remove(); if(fulAvatarVal.length == 0) { $("#container").prepend(errorTip.format(‘請選擇要上傳的文件‘)); return false; } var extName = fulAvatarVal.substring(fulAvatarVal.lastIndexOf(‘.‘),fulAvatarVal.length).toLowerCase(); if(extName != ‘.png‘ && extName != ‘.jpg‘){ $("#container").prepend(errorTip.format(‘只支持png和jpg格式圖片‘)); return false; } return true; }) }); </script>
這裏一定要註意表單的enctype屬性,這個就不多作解釋了,如果是初次接觸,看看http://www.w3school.com.cn/tags/att_form_enctype.asp
2.實現index.js中上傳邏輯
var express = require(‘express‘) router = express.Router(), formidable = require(‘formidable‘), fs = require(‘fs‘), TITLE = ‘formidable上傳示例‘, AVATAR_UPLOAD_FOLDER = ‘/avatar/‘ /* GET home page. */ router.get(‘/‘, function(req, res) { res.render(‘index‘, { title: TITLE }); }); router.post(‘/‘, function(req, res) { var form = new formidable.IncomingForm(); //創建上傳表單 form.encoding = ‘utf-8‘; //設置編輯 form.uploadDir = ‘public‘ + AVATAR_UPLOAD_FOLDER; //設置上傳目錄 form.keepExtensions = true; //保留後綴 form.maxFieldsSize = 2 * 1024 * 1024; //文件大小 form.parse(req, function(err, fields, files) { if (err) { res.locals.error = err; res.render(‘index‘, { title: TITLE }); return; } var extName = ‘‘; //後綴名 switch (files.fulAvatar.type) { case ‘image/pjpeg‘: extName = ‘jpg‘; break; case ‘image/jpeg‘: extName = ‘jpg‘; break; case ‘image/png‘: extName = ‘png‘; break; case ‘image/x-png‘: extName = ‘png‘; break; } if(extName.length == 0){ res.locals.error = ‘只支持png和jpg格式圖片‘; res.render(‘index‘, { title: TITLE }); return; } var avatarName = Math.random() + ‘.‘ + extName; var newPath = form.uploadDir + avatarName; console.log(newPath); fs.renameSync(files.fulAvatar.path, newPath); //重命名 }); res.locals.success = ‘上傳成功‘; res.render(‘index‘, { title: TITLE }); }); module.exports = router;
註意:在public文件夾中創建avatar文件夾以供文件存放
運行結果
1.在app.js中添加8000端口的監聽
2.cd到項目根目錄,運行node app
3.瀏覽器上訪問 localhost:8000
4.上傳圖片
5.去上傳文件夾中查看
大功告成!
部分疑惑解析
有一些在代碼中有註釋的我就不解釋了
1.怎麽沒看到上傳?
註意:form.parse 再看看formidable的解釋
Automatically writing file uploads to disk
2.為什麽需要fs.renameSync
原因和上一個問題有關,它會自動被上傳到用戶的臨時目錄(這個可以把files.fulAvatar.path輸出來看一下便知) http://nodejs.org/docs/latest/api/fs.html#fs_fs_renamesync_oldpath_newpath
3.可不可以看到上傳進度
可以,https://github.com/felixge/node-formidable#events (仔細看看events,可能有你要用的其它部分)
但是只是在控制臺輸出,想在前端去顯示進度條是不行的(沒有去研究,想想別的辦法應該也可以)
4.文件名想命名UUID不重復,在nodejs中怎麽辦?
可以使用node-uuid,調用簡單 https://github.com/broofa/node-uuid
...
其它的留言問吧^_^!
寫在之後
功能比較簡單,代碼也是示例風格,大家主要關註一下使用
代碼結構優化方向:
1.比如文件後綴這一類的方法可以放到一個pub.js中,此js專門用於這些公有方法
2.可以利於返回值的方式去返回數據,前端根據返回值做出相應的提示
3.可以利於jquery.form.js去提交表單,post中用res.json方法返回值,優化體驗(同樣引用這個js也會增大頁面體積)
....
總之是個小例子,大家將就著看看吧^_^!
文章來源:https://www.cnblogs.com/zhongweiv/p/nodejs_express_formidable.html
Nodejs學習筆記(八)—Node.js + Express 實現上傳文件功能(felixge/node-formidable)