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 相关文章推荐
极酷的javascirpt,让你随意编辑任何网页
Feb 25 Javascript
JavaScript判断窗口是否最小化的代码(跨浏览器)
Aug 01 Javascript
初窥JQuery(二)事件机制(2)
Dec 06 Javascript
最新28个很棒的jQuery 教程
May 28 Javascript
基于jquery的网站幻灯片切换效果焦点图代码
Sep 15 Javascript
jQuery获得内容和属性方法及示例
Dec 02 Javascript
判断横屏竖屏(三种)
Feb 13 Javascript
vue实现手机号码抽奖上下滚动动画示例
Oct 18 Javascript
使用vue的v-for生成table并给table加上序号的实例代码
Oct 27 Javascript
JavaScript callback回调函数用法实例分析
May 08 Javascript
vue项目如何刷新当前页面的方法
May 18 Javascript
vue随机验证码组件的封装实现
Feb 19 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实现的带超时功能get_headers函数
2015/02/10 PHP
简单了解WordPress开发中update_option()函数的用法
2016/01/11 PHP
简单理解PHP的面向对象编程方式
2016/05/17 PHP
PHP面向对象自动加载机制原理与用法分析
2016/10/14 PHP
jQuery 使用手册(二)
2009/09/23 Javascript
javascript qq右下角滑出窗口 sheyMsg
2010/03/21 Javascript
js函数中onmousedown和onclick的区别和联系探讨
2013/05/19 Javascript
鼠标滑在标题上显示图片的JS代码
2013/11/19 Javascript
浅析jQuery1.8的几个小变化
2013/12/10 Javascript
理解JavaScript事件对象
2016/01/25 Javascript
盘点javascript 正则表达式中 中括号的【坑】
2016/03/16 Javascript
Jquery AJAX POST与GET之间的区别详细介绍
2016/10/17 Javascript
jQuery实现web页面樱花坠落的特效
2017/06/01 jQuery
vue+jquery+lodash实现滑动时顶部悬浮固定效果
2018/04/28 jQuery
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
2019/09/19 Javascript
谈谈JavaScript令人迷惑的==与+
2020/08/31 Javascript
多个Vue项目部署到服务器的步骤记录
2020/10/22 Javascript
Python标准库内置函数complex介绍
2014/11/25 Python
python装饰器-限制函数调用次数的方法(10s调用一次)
2018/04/21 Python
python3 对list中每个元素进行处理的方法
2018/06/29 Python
Python爬虫使用脚本登录Github并查看信息
2018/07/16 Python
使用Python制作自动推送微信消息提醒的备忘录功能
2018/09/06 Python
PyCharm代码回滚,恢复历史版本的解决方法
2018/10/22 Python
Windows下Python3.6安装第三方模块的方法
2018/11/22 Python
Python 做曲线拟合和求积分的方法
2018/12/29 Python
Python3使用Matplotlib 绘制精美的数学函数图形
2019/04/11 Python
python中tkinter的应用:修改字体的实例讲解
2019/07/17 Python
django 链接多个数据库 并使用原生sql实现
2020/03/28 Python
Jupyter Notebook 实现正常显示中文和负号
2020/04/24 Python
课改先进个人汇报材料
2014/01/26 职场文书
《灯光》教学反思
2014/02/08 职场文书
纪检干部现实表现材料
2014/08/21 职场文书
python批量更改目录名/文件名的方法
2021/04/18 Python
Python3 多线程(连接池)操作MySQL插入数据
2021/06/09 Python
mybatis 获取无数据的字段不显示的问题
2021/07/15 Java/Android
Python进程池与进程锁之语法学习
2022/04/11 Python