技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> nodejs文件无刷新上传

nodejs文件无刷新上传

浏览:1313次  出处信息

   文件上传是网站最基本的操作之一。这两天研究了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实现文件上传还是挺简单的,完整代码请戳这

参考

建议继续学习:

  1. 为什么我们要从 NodeJS 迁移到 Ruby on Rails    (阅读:5449)
  2. Nodejs和MongoDB初体验    (阅读:5017)
  3. JavaScript,只有你想不到    (阅读:5087)
  4. Codeigniter里的无刷新上传    (阅读:4589)
  5. 使用socket.io和node.js搭建websocket应用    (阅读:4350)
  6. node.js调研与服务性能测试    (阅读:3650)
  7. 基于express+socket.io的nodejs聊天室    (阅读:3581)
  8. nodejs教程:配置nodejs.exe的windows目录结构    (阅读:3563)
  9. 渐进增强的无刷新多图片上传控件(iFrame+HTML5)    (阅读:3425)
  10. nodejs教程:安装及配置app.js文件    (阅读:2627)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1