基于Blod的ajax进度条下载实现
普通的浏览器下载
在web开发中,如果要实现下载功能,往往都是使用新开web页面或者是使用iframe的形式。实现起来其实很简单:
<atarget="_blank"href="download.zip">点击下载</a>或者<iframestyle="display:none"src="download.zip"></iframe>
用户点击a标签弹出一个新页签后,或者是打开了iframe后,浏览器就会接受一个下载响应,并下载附件。其实所谓附件下载,就是在浏览器读到响应报文的头之后,浏览器生成一个下载提示框,在用户确定后会继续下载文件。文件其实就是个流,所谓流就是一个传输的过程,浏览器会自动管理这个传输过程,会自动生成进度条、停止下载按钮、继续继续按钮、取消下载按、显示更新下载的字节数钮等。这些都是浏览器自动为我们做的,整个过程不受我们控制。
ajax下载
浏览器对下载的支持基本上已经能满足我们的需求,一般场景下再探索其他下载方式意义不大。但是还是有些场景是浏览器下载不能满足的,比如要求我们的web应用对下载进度的进行监控,或者下载完成后触发特定事件,或者web应用可以自动取消下载过程,或者使用worker创建一个后台运行的下载等等。对于以上情况我们都可以采用基于Blod对象的ajax下载。
ajax下载附件和ajax上传附件一样,需要浏览器支持ajax2.0。其实所谓下载和和普通的ajax请求没什么区别,都是对一个url地址做请求,但是下载一般都是二进制文件,不是文本对象或者json对象,需要JavaScript提供一个对够封装这个二进制文件的类型,这就是blod。因此要设置响应的类型responseType的值为“blod”:
var xhr =newXMLHttpRequest(); xhr.open(option.type? option.type.toUpperCase() : 'GET', url, true); xhr.responseType= 'blob';
要求XMLHttpRequest对象的responseType字段值是blob。那么blod对象又是什么?
blod对象
MDN对其描述为:
Blob对象是包含有只读原始数据的类文件对象。Blob对象中的数据并不一定得是JavaScript 中的原生形式。File接口基于 Blob,继承了Blob的功能,并且扩展支持用户计算机上的本地文件。通过Blob对象我们可以将一个二进制流封装为一个对象。
如果你了解过html5的file相关的api,你对于blod对象应该不会是陌生。blod能够把一个字节流封装为一个文件,将XMLHttpRequest对象的responseType值是blob,我们可以把响应体当做是一个blob对象处理。
xhr.onload = function() {//对于重定向的文件不予理会 if (this.status >= 200 && this.status < 300) {var blob = new Blob([this.response], {type: this.response.type});} }
使用ajax下载文件,再将文件保存为blob对象,缓存在浏览器中。那么如何让用户将文件保存到硬盘上呢?
将blob对象保存在硬盘上
我们可以效仿浏览器下载,生成一个a标签或者iframe,再生成一个url,这样就回到了浏览器下载了,浏览器会自动生成一个保存附件的窗口。url可以使用URL.createObjectURL(blob)方法获得,URL.createObjectURL支持Blob对象和File对象,能够生成一个虚拟的url使当前用户可以访问到这些对象,当然也包括下载。不同于直接从服务器下载,这里的下载是客户端内部的,不走网络io,所以下载几乎是瞬时的。不过生成完这个url后,还要将其释放,否则blob资源不会被垃圾回收,使用URL.revokeObjectURL就可以释放掉这个url,让blob资源释放。对于ie浏览器,有自己的一套Blob对象处理策略,就是msSaveOrOpenBlob和msSaveBlob两个navigator方法。
//ie的下载 if(window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, fileName); }else{//非ie的下载 var link = document.createElement('a'); link.href=window.URL.createObjectURL(blob); link.download=fileName; link.click(); window.URL.revokeObjectURL(link.href); }
进度条和取消下载
然后就是进度条和下载取消功能了,其实XMLHttpRequest对象是有个progress事件的,只是我们平时做ajax请求的时候都忽略他,毕竟一般请求都是瞬时的,不需要为其设置进度条。但是ajax下载却不一样,下载附件是需要时间的,因此为其开发个进度条还是很有必要的,监听progress事件,我们就可以获取下载进度。
使用XMLHttpRequest对象的abort函数可以取消下载,此外load事件可以监听到下载完成,error事件可以监听到下载失败。总之,ajax下载和一个普通的ajax请求的事件和方法是完全一样的。
性能优化和同源策略
ajax下载和长连接一样,会比普通请求占用更多带宽,尤其下载对带宽占用更是严重。因此下载过程中可能会阻塞其他的ajax请求,所以建议ajax下载的资源和其他请求的资源使用不同的域名,但是这样又会带来新的问题——同源策略问题。
同源策略是浏览器安全的基石,如果没有同源策略随便一个网站都可以发出csrf攻击。如果不能保证下载的资源的url和当前页面的url同源,就会触发同源策略导致下载失败,因此需要做ajax跨域处理。相比iframe和新页签的下载方法(事实上iframe也有同源策略,要求iframe里面的页面和父页面不能访问对方的内容,但是下载功能不涉及这种访问对方的内容操作,所以iframe下载是不受同源策略影响的),ajax下载本质上还是ajax,因此会受到浏览器同源策略的影响。所以如果下载非同源的附件,就需要附件所在的服务器支持cors,如果服务器需要访问cookie,还要将XMLHttpRequest对象的withCredentials设置为true。
同时出于同源策略的原因,我们不能使用ajax的形式去下载第三方资源,因为通常的下载服务都不会做cors处理的,比竟iframe下载或者新页签下载的方式是不受同源策略影响的,所以无需做cors处理。这大大限制了ajax下载的适用度。
总结:
最后我们再总结一下ajax下载的使用场景:
1.需求对下载进度的进行监控的场景,比如发现用户下载进度过慢,主动提供其他解决方案。
2.需要下载完成后触发特定事件,例如弹出一个桌面提示Notification。
3.需要提供一个后台下载。例如我们可以在用户打开网页后将附件偷偷地下载下来再缓存起来,等到用户真的想下载附件时候直接保存在本地。我们甚至可以借助worker创建一个后台线程,从而还能保证下载过程不会影响页面正常渲染。
4.需要下载后不保存在硬盘中,而是webapp直接处理附件。例如pdf.js,就是采用的ajax下载。
最后奉上笔者的一个ajax下载的demo: https://github.com/laden666666/ajaxDownloadDemo
基于Blod的ajax进度条下载实现相关推荐
- nodejs ajax进度条,Ajax异步文件上传与NodeJS express服务端处理的示例分析
Ajax异步文件上传与NodeJS express服务端处理的示例分析 发布时间:2021-07-24 11:17:21 来源:亿速云 阅读:79 作者:小新 这篇文章主要介绍Ajax异步文件上传与N ...
- ajax 进度条 php,php – Jquery :: Ajax提供进度条?
您可以通过.html()将动画gif加载到结果区域,直到ajax函数返回结果.只是一个想法 关于jquery ui进度条,间歇地通过你的脚本,你会想要一个表示完成百分比的数值作为一个赋值的javasc ...
- java ajax 进度条_java使用ajax实现进度条
在最近的一个项目中,有一个上传功能:上传一个cvs文件,然后解析此文件并写入数据库 由于经常需要传很大的文件,客户完成此功能往往需要40分钟,在这个过程中,页面也没有任何提示,用户体验非常不好? 为何 ...
- 基于pyqt5 构建弹窗进度条,在大型计算中实时显示进度
在大型计算时(例如神经网络训练),经常会遇到计算时间过长,无法知道当前的计算进度,无法判断程序是否进入死循环等问题.采用进度条可以在一定程度上了解当前进度,判断后续所需的计算时间,缓解等待过程中的焦虑 ...
- 基于python的打印进度条、计算用时
打印进度条 for range形式 import time for i in range(11):time.sleep(0.5)print('\r当前进度:{0}{1}%'.format('▉'*i, ...
- MFC基于Progress动态滚动进度条
1. 在对话框上新建一个滚动条控件IDC_PROGRESS1 2. 关联一个control类型的变量m_progress 具体步骤:右击进度条,添加变量 常用方法: **SetRange方法用来设置进 ...
- 从零开始实现一个基于贝塞尔曲线的进度条动画
开发环境 Android Studio 3.6.3 前言 在APP开发的时候,UI的效果图里提供了一个比较炫酷的进度条效果,琢磨着找了几篇资料实现了. 效果预览 先来看下Demo的效果,实际效果会比这 ...
- android 自定义view实现应用宝进度条下载效果
这个有好多种做法,我就讲二种方法,第一种方法就是自定义一个view,通过canvas画线就可以,只要把paint的width改成view的高度就行: package com.day01; import ...
- Ajax进度条动画制作网址
http://ajaxload.info/ http://preloaders.net/
最新文章
- 3D惯导Lidar仿真
- 关于手机的完美ROOT和一些问题的解决【OPPOx903亲测通过】
- WEB 3.0(非技术版)
- Webshell免杀绕过waf
- Web框架之Django_03 路由层了解(路有层 无名分组、有名分组、反向解析、路由分发 视图层 JsonResponse,FBV、CBV、文件上传)
- 《精通正则表达式》笔记
- 打造 通用的 支持多数据库 操作的 DBHelper
- 专题2-通过按键玩中断\第1课-中断处理流程深度剖析-lesson1
- Dotnet的垃圾回收
- 编程之美-2.17-数组循环移位
- C语言-附加-给一个数求最大质数(完整代码)
- 使用Firebase、Angular 8和ASP.NET Core 3.1保护网站
- 163邮箱苹果设置不成功_苹果变安卓不是不可能,Corellium让iPhone成功安装安卓系统...
- 【转】从事IT行业的应该如何学习最高效的休息方式
- 不骗你,全网首创的超硬核的万字SQL题
- 计算机显示磁盘但是打不开怎么办,移动硬盘显示盘符但打不开解决教程
- 如何用python画帆船_简单几步,100行代码用Python画一个蝙蝠侠的logo
- 乌云平台公开漏洞、知识库爬虫和搜索——乌云所有离线数据
- 前端图片在线转换Base64 图片编码Base64
- 网络抓包工具 wireshark 入门教程
热门文章
- linux恢复到硬盘分区,linux下恢复硬盘分区数据
- Gilde框架的使用(未完待续)和glide-transformations(图形变换)
- nodejs+vue 学分置换管理系统
- CDA数据分析浙江师范大学 第二期“正阳旅游大数据创新创业班”项目报告会暨结业典礼顺利开启...
- 应急响应 | 通过Python对Windows事件日志进行解析
- tinymce 使用及自定义上传插件
- python 文本分类卡方检验_文本分类学习 (四) 特征选择之卡方检验
- 记一次H5模型转换TFLite格式并做8bit量化的过程
- 在西安,有多少家企业在招聘程序员,设计师?
- 【浅谈】游戏故事编写指南:10个基本步骤