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 相关文章推荐
javascript Zifa FormValid 0.1表单验证 代码打包下载
Jun 08 Javascript
jQuery DIV弹出效果实现代码
Jul 03 Javascript
js变量以及其作用域详解
Jul 18 Javascript
Textarea与懒惰渲染实现代码
Jan 04 Javascript
JQuery统计input和textarea文字输入数量(代码分享)
Dec 29 Javascript
Node.js+jade抓取博客所有文章生成静态html文件的实例
Sep 19 Javascript
Vue使用mixins实现压缩图片代码
Mar 14 Javascript
JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】
Feb 21 Javascript
Angular8 Http拦截器简单使用教程
Aug 20 Javascript
详解Angular Karma测试的持续集成实践
Nov 15 Javascript
解决Vue.js应用回退或刷新界面时提示用户保存修改问题
Nov 24 Javascript
JavaScript展开运算符和剩余运算符的区别详解
Feb 18 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学习资源和链接.
2006/12/05 PHP
mysql中存储过程、函数的一些问题
2007/02/14 PHP
PHP 截取字符串专题集合
2010/08/19 PHP
解析php中两种缩放图片的函数,为图片添加水印
2013/06/14 PHP
thinkphp文件引用与分支结构用法实例
2014/11/26 PHP
CodeIgniter针对数据库的连接、配置及使用方法
2016/03/03 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
LazyForm jQuery plugin 定制您的CheckBox Radio和Select
2009/10/24 Javascript
js 效率组装字符串 StringBuffer
2009/12/23 Javascript
jQuery UI Autocomplete 1.8.16 中文输入修正代码
2012/04/16 Javascript
用jquery写的菜单从左往右滑动出现
2014/04/11 Javascript
谈谈JavaScript中function多重理解
2015/08/28 Javascript
JavaScript常用标签和方法总结
2015/09/01 Javascript
微信小程序-图片、录音、音频播放、音乐播放、视频、文件代码实例
2016/11/22 Javascript
Vue.js实战之组件的进阶
2017/04/04 Javascript
bootstrap3 dialog 更强大、更灵活的模态框
2017/04/20 Javascript
JavaScript代码判断输入的字符串是否含有特殊字符和表情代码实例
2017/08/17 Javascript
vue实现压缩图片预览并上传功能(promise封装)
2019/01/10 Javascript
react项目如何使用iconfont的方法步骤
2019/03/13 Javascript
JQuery发送ajax请求时中文乱码问题解决
2019/11/14 jQuery
JS校验与最终登陆界面功能完整示例
2020/01/13 Javascript
python连接数据库的方法
2017/10/19 Python
django实现同一个ip十分钟内只能注册一次的实例
2017/11/03 Python
python读取xlsx的方法
2018/12/25 Python
使用python os模块复制文件到指定文件夹的方法
2019/08/22 Python
用Python 执行cmd命令
2020/12/18 Python
iframe与window.onload如何使用详解
2020/05/07 HTML / CSS
美国最大网上鞋店:Zappos
2016/07/25 全球购物
中国综合网上购物商城:苏宁易购
2016/08/09 全球购物
毕业生自我鉴定范文
2013/11/08 职场文书
电大毕业生自我鉴定
2013/11/10 职场文书
个人事迹材料怎么写
2014/12/30 职场文书
电影焦裕禄观后感
2015/06/09 职场文书
二胎满月酒致辞
2015/07/29 职场文书
用基于python的appium爬取b站直播消费记录
2021/04/17 Python
python如何进行基准测试
2021/04/26 Python