node.js实现带进度条的多文件上传


Posted in Javascript onMarch 27, 2020

用node.js实现多文件上传并携带进度条的demo,供大家参考,具体内容如下

这个独立封装的需求来自一个朋友公司,他说需要写一个带进度条动画的批量上传文件的组件,结果他们后端跟他说不能多文件上传,我一听就很尴尬了,怎么可能不能多文件呢哈哈,后来我只是告诉他进度条的实现方式,在过了2天后我一直对此事耿耿于怀,所以干脆自己动手用node写了一个多文件上传的demo,并记录下来。

  • 前端: http请求为自己封装的一个原生请求函数,一切以原生代码为主;
  • 后端(nodeJs): express + multer,自定义 multer 包的 diskStorage 函数;

直接上demo吧,我加上一点注解就好,就不用详细说明了, 其中写了一个测试接口用来测试,可以不用管;

// 前端 upload.html
<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>上传文件demo</title>
 <style media="screen">
  .progress{
  width: 50%;
  height: 5px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-top: 10px;
  position: relative;
  }
  .progress>span{
  display: inline-block;
  position: absolute;
  border-radius: 4px;
  top: 0;
  left: 0;
  height: 100%;
  width: 0;
  background-color: rgb(98, 230, 74);
  transition: width 0.3s ease-out;
  }
 </style>
 </head>
 <body>
 <input id="file" type="file" multiple>
 <div class="progress">
  <span></span>
 </div>
 <script type="text/javascript">
  var http = function (option) {
  // 过滤请求成功后的响应对象
  function getBody (xhr) {
   var text = xhr.responseText || xhr.response
   if (!text) {
   return text
   }

   try {
   return JSON.parse(text)
   } catch (err) {
   return text
   }
  }

  var xhr = new XMLHttpRequest();
  // 自定义 beforeSend 函数
  if(option.beforeSend instanceof Function) {
   if (option.beforeSend(xhr) === false) {
   return false
   }
  }

  xhr.onreadystatechange = function () {
   if (xhr.status === 200) {
   if (xhr.readyState === 4) {
    // 成功回调
    option.onSuccess(getBody(xhr))
   }
   }
  }

  // 请求失败
  xhr.onerror = function (err) {
   option.onError(err)
  }

  xhr.open(option.type, option.url, true)

  // 当请求为上传文件时回调上传进度
  if (xhr.upload) {
   xhr.upload.onprogress = function (event) {
   if (event.total > 0) {
    event.percent = event.loaded / event.total * 100;
   }
   // 监控上传进度回调
   if (option.onProgress instanceof Function) {
    option.onProgress(event)
   }
   }
  }

  // 自定义头部
  const headers = option.headers || {}
  for (var item in headers) {
   xhr.setRequestHeader(item, headers[item])
  }

  xhr.send(option.data)
  }
 
 // 测试接口
  http({
  type: 'POST',
  url: '/test',
  data: JSON.stringify({
   name: 'yolo'
  }),
  onSuccess: function (data) {
   console.log(data)
  },
  onError: function (err) {
   console.log(err)
  }
  })
  document.getElementById('file').onchange = function () {
  var fileList = this.files, formData = new FormData();
  Array.prototype.forEach.call(fileList, function (file) {
   formData.append(file.name, file)
  })
  // 当上传的数据为 file 类型时,请求的格式类型自动会变为 multipart/form-data, 如果头部格式有特定需求,在我的 http 函数中传入 headers<Object> 即可,大家可自己查看,我这里没有什么特殊处理所以就不传了
  http({
   type: 'POST',
   url: '/upload',
   data: formData,
   onProgress: function (event) {
   console.log(event.percent)
   document.querySelector('.progress span').style.width = event.percent + '%';
   },
   onSuccess: function (data) {
   console.log('上传成功')
   },
   onError: function (err) {
   alert(err)
   }
  })
  }
 </script>
 </body>
</html>

后端所用的一些东西我放在这

express中间件-multer
express 4.x 文档

// 后端(node.js) upload.js
var express = require('express');
var path = require('path');
var fs = require('fs');
var app = express();
var bodyParser = require('body-parser'); // 过滤请求头部相应格式的body
var multer = require('multer');
var chalk = require('chalk'); // 只是一个 cli 界面字体颜色包而已
var log = console.log.bind(console);

app.use(express.static('static'));
// 接受 application/json 格式的过滤器
var jsonParser = bodyParser.json()
// 接受 application/x-www-form-urlencoded 格式的过滤器
var urlencodedParser = bodyParser.urlencoded({ extended: false })
// 接受 text/html 格式的过滤器
var textParser = bodyParser.text()

// 自定义 multer 的 diskStorage 的存储目录与文件名
var storage = multer.diskStorage({
 destination: function (req, file, cb) {
 cb(null, 'view')
 },
 filename: function (req, file, cb) {
 cb(null, file.fieldname)
 }
})

var upload = multer({ storage: storage })

// 页面渲染
app.get('/', function (req, res) {
 res.sendFile(path.join(__dirname, 'view/upload.html'));
})

app.post('/test', textParser, jsonParser, function (req, res) {
 log(req.body);
 var httpInfo = http.address();
 res.send({
 host: httpInfo.address,
 port: httpInfo.port
 })
})

// 对应前端的上传接口 http://127.0.0.1:3000/upload, upload.any() 过滤时不对文件列表格式做任何特殊处理
app.post('/upload', upload.any(), function (req, res) {
 log(req.files)
 res.send({message: '上传成功'})
})

// 监控 web 服务
var http = app.listen(3000, '127.0.0.1', function () {
 var httpInfo = http.address();
 log(`创建服务${chalk.green(httpInfo.address)}:${chalk.yellow(httpInfo.port)}成功`)
})

上传完毕后重新上传我没写动画重置,大家实际用的时候肯定是需要展示每个上传文件的,每次上传文件都对应着一个进度条,所以应该抽象为一个组件,至于组件的抽象我这就不详细写了,那个就很容易了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于JQuery的访问WebService的代码(可访问Java[Xfire])
Nov 19 Javascript
angular.foreach 循环方法使用指南
Jan 06 Javascript
Javascript中的arguments与重载介绍
Mar 15 Javascript
javascript记住用户名和登录密码(两种方式)
Aug 04 Javascript
基于jQuery实现自动轮播旋转木马特效
Nov 02 Javascript
微信JS-SDK坐标位置如何转换为百度地图坐标
Jul 04 Javascript
canvas 绘制圆形时钟
Feb 22 Javascript
vue 动态修改a标签的样式的方法
Jan 18 Javascript
jquery实现直播弹幕效果
Nov 28 jQuery
Windows下安装 node 的版本控制工具 nvm
Feb 06 Javascript
原生JS生成指定位数的验证码
Oct 28 Javascript
给原生html中添加水印遮罩层的实现示例
Apr 02 Javascript
基于Express框架使用POST传递Form数据
Aug 10 #Javascript
Vue实现点击显示不同图片的效果
Aug 10 #Javascript
vue+eslint+vscode配置教程
Aug 09 #Javascript
一个手写的vue放大镜效果
Aug 09 #Javascript
详解Vue-cli3.X使用px2rem遇到的问题
Aug 09 #Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
Aug 09 #Javascript
小程序Request的另类用法详解
Aug 09 #Javascript
You might like
php 静态页面中显示动态内容
2009/08/14 PHP
php处理文件的小例子(解压缩,删除目录)
2013/02/03 PHP
PHP远程采集图片详细教程
2014/07/01 PHP
PHP实践教程之过滤、验证、转义与密码详解
2017/07/24 PHP
JavaScript DOM 学习第七章 表单的扩展
2010/02/19 Javascript
Jquery带搜索框的下拉菜单
2013/05/06 Javascript
js实现点击图片自动提交action的简单方法
2016/10/16 Javascript
js仿百度音乐全选操作
2017/01/13 Javascript
zTree实现节点修改的实时刷新功能
2017/03/20 Javascript
Angular 4依赖注入学习教程之ClassProvider的使用(三)
2017/06/04 Javascript
详解原生js实现offset方法
2017/06/15 Javascript
jQuery 实现鼠标画框并对框内数据选中的实例代码
2017/08/29 jQuery
微信小程序基于slider组件动态修改标签透明度的方法示例
2017/12/04 Javascript
js获取html页面代码中图片地址的实现代码
2018/03/05 Javascript
vue获取当前点击的元素并传值的实例
2018/03/09 Javascript
基于JS实现web端录音与播放功能
2019/04/17 Javascript
JS中FormData类实现文件上传
2020/03/27 Javascript
微信公众号网页分享功能开发的示例代码
2020/05/27 Javascript
JavaScript 声明私有变量的两种方式
2021/02/05 Javascript
[47:20]DAC2018 4.4 淘汰赛 Optic vs Mineski 第一场
2018/04/05 DOTA
在DigitalOcean的服务器上部署flaskblog应用
2015/12/19 Python
对python中的乘法dot和对应分量相乘multiply详解
2018/11/14 Python
基于python的docx模块处理word和WPS的docx格式文件方式
2020/02/13 Python
Python自动化之UnitTest框架实战记录
2020/09/08 Python
细说CSS3中box属性中的overflow-x属性和overflow-y属性值的效果
2014/07/21 HTML / CSS
AHAVA美国官方网站:死海海泥护肤品牌
2016/10/18 全球购物
澳大利亚在线购买葡萄酒:The Wine Collective
2020/02/20 全球购物
旅游管理毕业生自荐信
2013/11/05 职场文书
金融专业大学生职业生涯规划范文
2014/01/16 职场文书
2014植树节活动总结
2014/03/11 职场文书
旅游活动总结
2014/08/27 职场文书
2014年政风行风自查自纠报告
2014/10/21 职场文书
复兴之路观后感
2015/06/02 职场文书
小学语文新课改心得体会
2016/01/22 职场文书
公司晚会主持词
2019/04/17 职场文书
Django程序的优化技巧
2021/04/29 Python