關於formidable
NodeJs實現圖片上傳,此處主要用了插件:formidable
github上關於formidable的資料如下:
https://github.com/felixge/node-formidable
https://www.npmjs.org/package/formidable
創建項目安裝formidable
1,創建項目sampleUpload
cd 工作目錄
express -e sampleUpload
2,修改package.json文件,添加formidable依賴項
{ "name": "sampleUpload", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "ejs": "~2.3.3", "express": "~4.13.1", "morgan": "~1.6.1", "serve-favicon": "~2.3.0", "formidable":"latest" } }
3,安裝依賴項
cd sampleUpload && npm install
安裝成功,開始完成這個功能,文件目錄如下圖:
樣式主要使用了bootstrap 3.0.3 https://github.com/twbs/bootstrap/releases/tag/v3.0.3
JQuery: 官方下載
不在bootstrap包中的兩個css文件代碼如下:

body { min-height: 2000px; } .navbar-static-top { margin-bottom: 19px; } navbar-static-top.css

body { padding-top: 40px; padding-bottom: 40px; background-color: #eee; } .form-signin { max-width: 330px; padding: 15px; margin: 0 auto; } .form-signin .form-signin-heading, .form-signin .checkbox { margin-bottom: 10px; } .form-signin .checkbox { font-weight: normal; } .form-signin .form-control { position: relative; font-size: 16px; height: auto; padding: 10px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .form-signin .form-control:focus { z-index: 2; } .form-signin input[type="text"] { margin-bottom: 10px; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } .form-signin input[type="password"] { margin-bottom: 10px; border-top-left-radius: 0; border-top-right-radius: 0; } signin.css
app.js文件中添加端口號8200(可以隨便定,只要不和其他的程序沖突即可)
app.listen(8200,function(err){ console.log("server started"); });
app.js中修改模板引擎為.html文件
app.set('view engine', 'html'); //設置模板文件的后綴名為.html //運行ejs模板 app.engine(".html",require("ejs").__express);
index.html文件中構建表單並實現前端驗證

<!DOCTYPE html> <html> <head> <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> <h1><%= title %></h1> <div id="container" class="container"> <% if(locals.success){%> <div id="alt_success" 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> <script src="/javascripts/jquery-2.1.4.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(); var 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(); alert(extName); if(extName!=".png" && extName!=".jpg"){ $("#container").prepend(errorTip.format("只支持png和jpg格式圖片")); return false; } return true; }); }) </script> </html>
這里一定要注意表單的enctype屬性,這個就不多作解釋了,如果是初次接觸,看看http://www.w3school.com.cn/tags/att_form_enctype.asp
實現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 = ''; //后綴名 console.log("files.fulAvatar.type="+files.fulAvatar.type); 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文件夾以供文件存放
運行結果:
在項目中遇到的問題:
由於在html中代碼寫成:
<input id="fulAvatar" name="fulAvater" type="file" class="form-control" /><br/>
而在index.js中部分代碼如下:
form.parse(req, function(err, fields, files) { if (err) { res.locals.error = err; res.render('index', { title: TITLE }); return; } var extName = ''; //后綴名 console.log("files.fulAvatar.type="+files.fulAvatar.type); 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 });
運行之后總是報以下異常:
雖然報異常,但是上傳圖片確是成功的,界面顯示上傳成功。
原因是因為:
雖然form.parse方法中有異常,但是它是異步的,不妨礙以下代碼的執行:
res.locals.success = '上傳成功';
res.render('index', { title: TITLE });
上傳成功是因為:
只要調用了form.parse方法就可以上傳成功。
最終找到原因是因為html中上傳控件的name值為:
<input id="fulAvatar" name="fulAvater" type="file" class="form-control" /><br/>
與index.js中的files.fulAuatar不一致導致的。
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; }
把index.html中代碼為以下即可:
<input id="fulAvatar" name="fulAvatar" type="file" class="form-control" /><br/>
具體參考:
http://www.cnblogs.com/zhongweiv/p/nodejs_express_formidable.html#node_web_install