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 相关文章推荐
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
Jul 29 Javascript
js中更短的 Array 类型转换
Oct 30 Javascript
JS实现动态移动层及拖动浮层关闭的方法
Apr 30 Javascript
JavaScript实现级联菜单的方法
Jun 29 Javascript
详解Document.Cookie
Dec 25 Javascript
微信小程序 数据封装,参数传值等经验分享
Jan 09 Javascript
js清除浏览器缓存的几种方法
Mar 15 Javascript
js实现前端图片上传即时预览功能
Aug 02 Javascript
常见的浏览器存储方式(cookie、localStorage、sessionStorage)
May 07 Javascript
js神秘的电报密码 哈弗曼编码实现
Sep 10 Javascript
如何在Vue中使localStorage具有响应式(思想实验)
Jul 14 Javascript
在nuxt中使用路由重定向的实例
Nov 06 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中$this-&amp;gt;含义分析
2009/11/29 PHP
PHP 魔术函数使用说明
2010/05/14 PHP
PHP number_format() 函数定义和用法
2012/06/01 PHP
深入分析使用mysql_fetch_object()以对象的形式返回查询结果
2013/06/05 PHP
PHP操作MongoDB GridFS 存储文件的详解
2013/06/20 PHP
Yii2下点击验证码的切换实例代码
2017/03/14 PHP
PHP curl 或 file_get_contents 获取需要授权页面的方法
2017/05/05 PHP
Ubuntu上安装yaf扩展的方法
2018/01/29 PHP
php把字符串指定字符分割成数组的方法
2018/03/12 PHP
jQuery取id有.的值的方法
2014/05/21 Javascript
基于Bootstrap实现tab标签切换效果
2020/04/15 Javascript
BootStrap table表格插件自适应固定表头(超好用)
2016/08/24 Javascript
利用Query+bootstrap和js两种方式实现日期选择器
2017/01/10 Javascript
浅谈关于JS下大批量异步任务按顺序执行解决方案一点思考
2019/01/08 Javascript
vue中keep-alive、activated的探讨和使用详解
2020/07/26 Javascript
详解vue3中组件的非兼容变更
2021/03/03 Vue.js
解读Python编程中的命名空间与作用域
2015/10/16 Python
修复CentOS7升级Python到3.6版本后yum不能正确使用的解决方法
2018/01/26 Python
PyQt实现界面翻转切换效果
2018/04/20 Python
python实现百度OCR图片识别过程解析
2020/01/17 Python
使用python3 实现插入数据到mysql
2020/03/02 Python
python如何快速拼接字符串
2020/10/28 Python
Python接口自动化测试框架运行原理及流程
2020/11/30 Python
Python爬虫+Tkinter制作一个翻译软件的示例
2021/02/20 Python
Expedia泰国:预订机票、酒店和旅游包(航班+酒店)
2016/09/27 全球购物
面向中国市场的在线海淘美妆零售网站:Beauty House美丽屋
2021/03/02 全球购物
计算机开发个人求职信范文
2013/09/26 职场文书
办公室文书岗位职责
2013/12/16 职场文书
五一劳动节活动记录
2014/03/23 职场文书
员工试用期考核自我鉴定
2014/04/13 职场文书
热爱祖国的演讲稿
2014/05/04 职场文书
红色旅游心得体会
2014/09/03 职场文书
领导个人查摆剖析材料
2014/10/29 职场文书
2019年圣诞节祝福语集锦
2019/12/25 职场文书
再见,2019我们不负使命;你好,2020我们砥砺前行
2020/01/03 职场文书
Zabbix6通过ODBC方式监控Oracle 19C的详细过程
2022/09/23 Servers