2019独角兽企业重金招聘Python工程师标准>>>

 

大家有必要看到文末

xhr传统的AJAX传输对象,在做后台系统的时候经常遇到文件上传的情景,以往的xhr已经能够应对文件表格上传的功能,但如今遇到项目需求,上传的文件比较大数据表较多,为了提高用户体验有必要增加文件上传进度条,让用户知悉当前的操作进度,以免一直停留在空白页究竟有没有上传服务器都不清楚。此文用到的也还是AJAX的技术,XMLHttpRequest Level 2特性(也是老东西)

XHR2的事件例表:

attribute type Explanation
onloadstart loadstart When the request starts.
onprogress progress While loading and sending data.
onabort abort When the request has been aborted, either by invoking the abort() method or navigating away from the page.
onerror error When the request has failed.
onload load When the request has successfully completed.
ontimeout timeout When the author specified timeout has passed before the request could complete.
onloadend loadend When the request has completed, regardless of whether or not it was successful.

回顾AJAX基本知识

ajax基本结构

此文要做进度条,必须要在xhr.readyState === 3(解析,XMLHttpRequest对象开始持续读取服务器的响应)的状态中进行获取进度

组件结构

由于项目是基于Angular4开发,文件上传作为自定义组件进行封装,此文只解释如何获取进度情况,对于获取后的值如何回显到父组件等不作展开(父组件持续接受文件上传组件的进度情况,通过另外一个子组件去接收父组件接收到的进度情况并通过ngOnChanges(changes: SimpleChanges) 监听回显进度)

file-upload.component.html

<input type="file" accept=".xls,.xlsx,.et" name="file" (change)="onFileSelect($event)">

accept为H5新属性,当选择文件时默认只显示文件夹中的xls xlsx et后缀文件,当然也可以选择图片(image/png,image/gif)等。这仅是前端过滤文件选择用户最终还是能选择其他文件上传,入拖拽情况。

请避免使用该属性。应该在服务器端验证文件上传。

file-upload.component.ts

// 文件选择
onFileSelect(event) {// 选择需要过滤的excel文件后缀,前端过滤,不用服务器过滤let pos = event.target.files[0].name.lastIndexOf(".");let lastname = event.target.files[0].name.substring(pos + 1, event.target.files[0].name.length);let hz = 'xls xlsx et';if (hz.indexOf(lastname) >= 0) {// dataTransfer兼容谷歌火狐文件拖拽上传,但没获取到该属性this.files = event.dataTransfer ? event.dataTransfer.files : event.target.files;} else {this.files = undefined;}
}fileUpload(url: string) {//先判断上传文件的格式是否正确if (!this.files) {this.mask.info("warn", "请上传正确的文件格式");return;}// 进度百分比let progress = 0;// 通过formData做数据托管,避免做繁琐的字符串拼接地址let xhr = new XMLHttpRequest(),formData = new FormData();formData.append('file', this.files[0], this.files[0].name);// 监听upload事件的progress属性获取,进度百分比总长xhr.upload.addEventListener('progress', (e: ProgressEvent) => {if (e.lengthComputable) {progress = Math.round((e.loaded * 100) / e.total);}}, false);xhr.onreadystatechange = () => {// 通过后台返回的百分比去进行回显页面进度条if (xhr.readyState === 3) {let responseObject = xhr.responseText.split("|");let responseArr = [];let latestRespone;responseObject.forEach(val => {if (val && _.has(JSON.parse(val), 'percentage')) {latestRespone = JSON.parse(responseObject[xhr.responseText.split("|").length - 1]);}// 读取完百分比后把所有数据回显到界面上if (val && _.has(JSON.parse(val), 'errorObject')) {responseArr.push(JSON.parse(val)['errorObject']);latestRespone = { errorObject: responseArr };if (_.has(JSON.parse(val), 'success')) {latestRespone['success'] = JSON.parse(val)['success'];latestRespone['fail'] = JSON.parse(val)['fail'];}if (_.has(JSON.parse(val), 'filePath')) {latestRespone['filePath'] = JSON.parse(val)['filePath'];}}})this.progress.emit(latestRespone);}if (xhr.readyState === 4) {progress = 0;if (xhr.status >= 200 && xhr.status < 300) {/* 服务器返回的都是字符串,在这里需要做解析*//* let rh = xhr.getResponseHeader('Content-Type');let result;if (rh.indexOf('json') !== -1) {result = JSON.parse(xhr.responseText);} else if (rh.indexOf('xml') !== -1) {result = xhr.responseXML;} else {result = xhr.responseText;}this.success.emit(result); */} else {//上传失败//this.mask.info("error", "上传失败");}}};xhr.open('POST', url, true);let jwt = localStorage["jwt"];if (jwt) {xhr.setRequestHeader("Authorization", "Bearer " + jwt);} xhr.send(formData);
}

FormData 对象的使用

progress事件会在浏览器接收新数据期间周期性地触发。而onprogress事件处理程序会接收到一个event对象,其target属性是XHR对象,但包含着三个额外的属性:lengthComputable、loaded和total。其中,lengthComputable是一个表示进度信息是否可用的布尔值,loaded表示已经接收的字节数,total表示根据Content-Length响应头部确定的预期字节数。有了这些信息,我们就可以为用户创建一个进度指示器了。下面展示了为用户创建进度指示器的一个示例。

//get请求一般用来获取下载进度
xhr.onprogress = function (event) {var divStatus = document.getElementById("status");if (event.lengthComputable) {divStatus.innerHTML = "Recived" + event.loaded + " of " + event.total + " bytes";}
}
//post一般用来获取上传进度
xhr.upload.onprogress = function(e) {if (e.lengthComputable) {console.log(e.loaded / e.total * 100)}
}

总结:

看到这里,先跟大家说一声对不起这次的进度条并不是progress的产物,而是通过readyState===3解析后端返回的一条条数据进而回显进度百分比。这完全是后端做出来的进度条,目前这种方法也是能做到回显数据百分比显示。上面的xhr.upload.addEventListener('progress',...)仅是上传服务器的进度,此时并没有把服务器返回的数据带回来。这应该跟GET产生一个TCP数据包;POST产生两个TCP数据包有关系。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

正常情况当服务器响应到结束只会发送一大段信息,至于为什么能在readyState === 3就能获取多条后台返回的数据,完全是后端代码一个专业名词flush(),后端在解析完上传的文件后,每50条数据就会刷新一次,这样就可以达到前端接收每50条的进度情况,这摆明就是欺骗用户嘛。我发誓我是在了解上传文件进度条的时候才发现。

由于整篇文章没有过多的xhr2的progress前端进度条,接下来说说progress这货怎么玩。

function uploadFile() {var fd = new FormData();fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);var xhr = new XMLHttpRequest();xhr.upload.addEventListener("progress", uploadProgress, false);xhr.addEventListener("load", uploadComplete, false);xhr.open("POST", "http://localhost:4000");//修改成自己的接口xhr.send(fd);
}function uploadProgress(evt) {if (evt.lengthComputable) {var percentComplete = Math.round(evt.loaded * 100 / evt.total);document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';}else {document.getElementById('progressNumber').innerHTML = 'unable to compute';}
}function uploadComplete(evt) {/* 服务器端返回响应时候触发event事件*/alert(evt.target.responseText);
}

在这里已经不是我们古老的AJAX post做法,通过readyState判断状态来获取服务器返回数据,这里是通过xhr提供的几个方法(看文首)load用来返回json集合。load事件可以完全替代xhr.readyState的1,2,3,4四个状态,evt.target可以看做是xhr的同类。post上传文件到服务器,通过progress确实可以返回上传速度,但可能是我本地服务器的原因不管是多大的文件都很快上传完全,进度条的作用不明显,在这里做不到像文首动图的效果,因为数据响应是一次过,根本没有间隔的余地,只有从0到1,不会出现0.1 0.2的数据。

上面代码还有一个好玩的地方,就是怎么快速搭建一个假的服务器,以往我们都用一些软件模拟本地服务器如(wampmanager),用 json-server快速设置一个模拟后端,摒弃直接写假数据的低端做法。具体可以看Angular和RxJS的一些应用场景

文件带有进度的异步上传本质

XHR2:让使用纯JS实现上传进度条变成了可能

99%的人都理解错了HTTP中GET与POST的区别

前端下载服务器文件速度及进度的计算方法

转载于:https://my.oschina.net/u/2949632/blog/1542001

后台系统上传文件回显上传进度条相关推荐

  1. themyleaf 图片上传_javaEE --springboot #实现图片上传和回显 #单文件上传 #多文件上传 #ajax异步文件上传 (非常详细,从创建项目开始)...

    实现文件上传和回显 1.新建一个SpringBoot项目,选择 Spring Web 和 thymeleaf 依赖 .pow.xml文件下的依赖如下 2.根据下图,创建如下文件 3.直接上代码 配置文 ...

  2. element UI el-upload组件实现视频文件上传视频回显

    项目中需要提供一个视频介绍,使用Vue+Element UI中的el-upload组件实现视频上传及进度条展示,后台提供视频上传API并返回URL, 百度找了一番后最终实现了. HTML <el ...

  3. php多图片上传并回显,如何用input标签和jquery实现多图片的上传和回显功能

    本文主要记录如何用input标签和jquery实现多图片的上传和回显,不会涉及后端的交互,大概的效果看图 效果图 我们从零来做一个这样的demo 第一步: 我们先完善一下我们的页面,默认的input- ...

  4. 阿里云对象存储OSS图片上传并回显

    阿里云对象存储OSS图片上传并回显 Java代码实现 引入依赖 <!-- 引入阿里云OSS依赖--><dependency><groupId>com.aliyun. ...

  5. vue中使用wangeditor富文本编辑器(含图片上传和回显)

    最近在写vue的项目中,遇到一个需求,点击编辑,显示弹框,在弹框中的富文本编辑器中编辑自定义文本样式,可以上传图片并回显.编辑完成确定后显示在页面上. 首先先写一个editor.vue的页面.(建议单 ...

  6. java前端接收回显图片_图片上传并回显后端篇

    图片上传并回显后端篇 我们先看一下效果 继上一篇的图片上传和回显,我们来实战一下图片上传的整个过程,今天我们将打通前后端,我们来真实的了解一下,我们上传的文件,是以什么样的形式上传到服务器,难道也是一 ...

  7. layui富文本编辑器上传图片java_解决layui富文本编辑器图片上传无法回显的问题...

    layui富文本编辑器用起来挺方便的,但是不足的是不提供图片上传的接口,需要自己写上传接口,而且返回的数据类型要符合layui富文本编辑器图片上传插件的要求,否则图片可以上传成功,但是无法回显,这个问 ...

  8. springboot项目上传头像回显

    springboot项目使用ajax上传头像回显 先上效果图: 开始上传 点击提交 环境: springboot2.2.5.RELEASE jdk:1.8 thymeleaf:3.0.4.RELEAS ...

  9. Linux系统如何连接和上传文件到服务器上

    Linux系统如何连接和上传文件到服务器上(图形化界面) 一.Linux连接服务器 1.安装rdesktop sudo apt-get intall rdesktop 2.使用rdesktop指令打开 ...

最新文章

  1. tensorflow随笔 -QueueRunner
  2. Boost:gzifstream和gzofstream的测试程序
  3. 大道至简第七章第八章
  4. 20线程测试cpu性能软件,评测平台介绍、CPU多线程性能测试
  5. 烂泥:团购网站的购买流程
  6. 周三晚八点直播丨如何通过APEX 实现自动化运维
  7. 【2017-04-16】抽象类、接口、构造函数、重载和重写的区别、静态成员和方法
  8. rpcbind 、nfs无法启动问题
  9. jsp管理系统页面模板_Jsp+Ssh2+Mysql实现的CRM客户关系管理系统
  10. php5.2 zend解密,狐灵科技分享几款zend解密工具,可以解密zend5.2
  11. [转]WebQQ登录过程分析
  12. 滚动条组件,react-custom-scrollbars
  13. 咻咻验证码,见证百合网发展壮大!
  14. OA会议 04 (查询会议签字)
  15. windows10系统如何安装日语输入法
  16. 第十二周项目四----利用遍历思想求解图问题之输出所有路径
  17. 利用HTML完成用户注册界面设计,以及性别复选框、按钮链接跳转的实现
  18. 多媒体计算机主要有哪些基本特性,多媒体计算机的基本特性
  19. 如何用好 Google 搜索引擎?
  20. python人工智能项目实战 桑塔努·帕塔纳亚克 pdf_(特价书)Python人工智能项目实战...

热门文章

  1. DNS域名系统(二)
  2. sqlplus 乱码的资料
  3. linux,想说爱你真的很不容易!
  4. Undelete Plus 2.53
  5. vue实践06-项目实践
  6. jQuery中的css部分
  7. [SinGuLaRiTy] 二分图匈牙利算法
  8. MySQL Semisync
  9. CSS3属性 box-shadow
  10. SCMagazine: SIEM走出阴影,迈向光明