关于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