nodejs文件无刷新上传
文件上传是网站最基本的操作之一。这两天研究了NodeJs环境下的文件上传问题,使用到了ExpressJS-4.12.1框架和multiparty工具包。整个上传采用RFC1867协议,即基于HTML表单的文件上传协议。借助这个协议,为表单增加enctype="multipart/form-data"属性,再使用type为file的input控制来选择文件,然后便可用POST方法上传文件。
传统的表单上传,属于"同步上传"。也就是说,点击上传按钮后,网页"锁死",用户只能等待上传结束,然后浏览器刷新,跳到表单的action属性指定的网址。显然,“同步上传”用户体验差。本文采用iframe和ajax两种方式,实现文件无刷新“异步”上传。
iframe方式
iframe虽然有很多缺点,但是利用它解决文件无刷新上传却是一个非常nice的方案。好处显而易见,因为几乎所有浏览器都支持iframe,所以兼容性非常棒。
原理:将form表单的target属性指向一个页面中隐藏的iframe,这使得上传结束后,服务器将结果返回iframe窗口,所以当前页面就不会跳转了。其次,同域iframe可以调用当前页面的js函数,这样就能将服务器返回的信息,从iframe窗口传到上层页面。
关键代码如下:
上传页面:node-iframe.hbs
<!-- 用于上传的form表单 --> <form method="post" enctype="multipart/form-data" action="/file-upload/iframe" target="hidden_frame"> <div>用户:<input type="text" name="username"></div> <div>密码:<input type="password" name="password"></div> <div><input type="file" name="upload1" multiple="multiple"></div> <div><input type="file" name="upload2" multiple="multiple"></div> <input type="submit"> </form> <!-- 隐藏的iframe --> <iframe src="hidden_frame" id="hidden_frame" name="hidden_frame" style="display: none;"></iframe> <div id="msg"></div> <script> /* 结果回调函数 */ function callback(result) { document.getElementById("msg").innerHTML = "<span>"+result+"</span>"; } </script>
路由配置:index.js
/* GET node-iframe page. */ router.get('/node-iframe', function(req, res, next) { res.render('node-iframe', { title: 'node-iframe' }); }); /* handle file upload */ router.post('/file-upload', function(req, res, next) { var form = new multiparty.Form({ uploadDir: './uploadDir/'}); form.parse(req, function(err, fields, files) { console.log(files); // 文件信息 console.log(fields); // 普通信息 if (err) { console.log('parser error : ' + err); } else { // 考虑多文件上传 for (var p in files) { var file = files[p]; if (file[0].size == 0) continue; var uploadedPath = file[0].path; var dstPath = './uploadDir/' + file[0].originalFilename; fs.rename(uploadedPath, dstPath, function(err) { if (err) { console.log('rename error : ' + err); } else { console.log('rename ok!'); } }); } } // 注意返回的content-type为text/html res.writeHead(200, {'content-type': 'text/html'}); // 利用parent.callback()调用父级函数 res.write("<script>parent.callback('success!!!');</script>"); res.end(); }); return; });
ajax方式
HTML5提出了XMLHttpRequest对象的第二版,从此ajax能够上传文件了,这是真正的“异步上传”,主要是利用了FormData对象。需要注意的是,并非所有浏览器都完整地实现了XMLHttpRequest2级规范。
关键代码如下:
上传页面:node-ajax.hbs
<!-- 上传表单 --> <form method="post" enctype="multipart/form-data" id="uploadform"> <div>用户:<input type="text" name="username"></div> <div>密码:<input type="password" name="password"></div> <div><input type="file" name="upload1" multiple="multiple"></div> <div><input type="file" name="upload2" multiple="multiple"></div> <input type="button" id="upload" value="上传"> </form> <p id="msg"></p> <script src="/javascripts/jquery-2.1.1.min.js"></script> <script> $('#upload').click(function() { // 创建formdata对象 var formData = new FormData($('#uploadform')[0]); $.ajax({ url: '/file-upload', type: 'post', data: formData, cache: false, contentType: false, processData: false, success: function(data) { $('#msg').text('success!!'); }, error: function() { $('#msg').text('error!!'); } }); }); </script>
路由配置:index.js
/* GET node-ajax page. */ router.get('/node-ajax', function(req, res, next) { res.render('node-ajax', { title: 'node-ajax' }); }); /* handle file upload */ router.post('/file-upload', function(req, res, next) { var form = new multiparty.Form({ uploadDir: './uploadDir/'}); form.parse(req, function(err, fields, files) { console.log(files); // 文件信息 console.log(fields); // 普通信息 if (err) { console.log('parser error : ' + err); } else { // 考虑多文件上传 for (var p in files) { var file = files[p]; if (file[0].size == 0) continue; var uploadedPath = file[0].path; var dstPath = './uploadDir/' + file[0].originalFilename; fs.rename(uploadedPath, dstPath, function(err) { if (err) { console.log('rename error : ' + err); } else { console.log('rename ok!'); } }); } } // 返回 res.writeHead(200, {'content-type': 'text/plain'}); res.end(); }); return; });
代码合并
由于,两种上传方式的后台代码几乎一样,唯一区别在于返回的响应不一样。可通过路由规则(/file-upload/:way),将两段代码合并。
/* handle file upload */ router.post('/file-upload/:way', function(req, res, next) { var form = new multiparty.Form({ uploadDir: './uploadDir/'}); form.parse(req, function(err, fields, files) { console.log(files); // 文件信息 console.log(fields); // 普通信息 if (err) { console.log('parser error : ' + err); } else { // 考虑多文件上传 for (var p in files) { var file = files[p]; if (file[0].size == 0) continue; var uploadedPath = file[0].path; var dstPath = './uploadDir/' + file[0].originalFilename; fs.rename(uploadedPath, dstPath, function(err) { if (err) { console.log('rename error : ' + err); } else { console.log('rename ok!'); } }); } } // 不同的请求方式,不同的返回 var way = req.params.way; if (way === 'iframe') { res.writeHead(200, {'content-type': 'text/html'}); res.write("<script>parent.callback('success!!!');</script>"); } else if (way === 'ajax') { res.writeHead(200, {'content-type': 'text/plain'}); } res.end(); }); return; });
别忘了,修改action="/file-upload/iframe"和url: '/file-upload/ajax'。
结语
利用node实现文件上传还是挺简单的,完整代码请戳这!
参考
建议继续学习:
- 为什么我们要从 NodeJS 迁移到 Ruby on Rails (阅读:5457)
- JavaScript,只有你想不到 (阅读:5116)
- Nodejs和MongoDB初体验 (阅读:5024)
- Codeigniter里的无刷新上传 (阅读:4611)
- 使用socket.io和node.js搭建websocket应用 (阅读:4373)
- node.js调研与服务性能测试 (阅读:3665)
- 基于express+socket.io的nodejs聊天室 (阅读:3591)
- nodejs教程:配置nodejs.exe的windows目录结构 (阅读:3596)
- 渐进增强的无刷新多图片上传控件(iFrame+HTML5) (阅读:3450)
- nodejs教程:安装及配置app.js文件 (阅读:2645)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:chenjun 来源: 风影博客
- 标签: nodejs 刷新
- 发布时间:2016-02-20 16:47:13
- [46] 界面设计速成
- [42] Oracle MTS模式下 进程地址与会话信
- [41] 视觉调整-设计师 vs. 逻辑
- [40] IOS安全–浅谈关于IOS加固的几种方法
- [39] android 开发入门
- [38] 图书馆的世界纪录
- [38] 如何拿下简短的域名
- [37] 程序员技术练级攻略
- [37] 【社会化设计】自我(self)部分――欢迎区
- [34] 读书笔记-壹百度:百度十年千倍的29条法则