使用Ajax实现异步文件下载(支持IE)

使用Ajax实现异步文件下载(支持IE)

需求描述

1. 页面上下载文件,点击下载文件后页面无跳转
2. 下载按钮点击后disabled,文件可以下载后恢复可用
3. 后台准备文件可能会比较耗时,比如延迟2-5S,此时需要防止用户重复点击
4. 需要支持Chrome,IE浏览器

一开始采用的是js中window.location.href=path(或者window.open),这种方式写起来非常简单。但是因为后台直接是response的流输出,浏览器并不会刷新当前页面或者新打开一个窗口,这种情况下js代码无法监听后台数据何时真正的返回。故而想到了使用ajax的方式进行请求,监听到success后再恢复按钮可用。项目中使用了jquery,第一版代码如下:

	//禁用按钮
	$("#export").attr("disabled",false);
	$.ajax({
		type : "GET",
	    //请求的媒体类型
	    contentType : false,
	    processData : false,
	    //请求地址
	    url : "文件下载路径",
	    //请求成功
	    success : function(blob) {
	    	//恢复按钮可用
	   		$("#export").attr("disabled",true);
	    	//处理数据
	    	//如果是IE,使用msSaveOrOpenBlob
	    	if (window.navigator.msSaveOrOpenBlob) {
	        	navigator.msSaveOrOpenBlob(blob, fileName+'.xls');
	        }else{
	        	//不是IE,模拟a的点击事件
	        	var link=document.createElement("a");
	        	link.href=URL.createObjectURL(blob);
	        	link.style="visibility:hidden";
	       		link.download=fileName+".xls"; 
	       		document.body.appendChild(link);
	       		link.click();
	       		document.body.removeChild(link);	
	        }
	    },
	    error : function(){
			$("#export").attr("disabled",true);
			alert("数据下载异常,请重试!");
		}
	});

数据返回后有两种处理方式,对非IE的浏览器而言,可以选择在document中新增一个隐藏的a标签,然后模拟click事件就可以下载了。而对IE而言,这个方法是不生效的。需要使用

	navigator.msSaveOrOpenBlob(blob,fileName+'.xls')

以上代码进行测试,发现还是不行,处理到bolb数据的时候js会报错。这是因为jquery的ajax有封装,response的数据以字符串的方式解析了。此处下载的如果是doc,xls等文件肯定是不行的。其实应对也很简单,使用原生的XMLRequest对象进行处理即可。修改后的代码如下:

	//禁用按钮
	$("#export").attr("disabled",false);
	//使用原生的ajax处理请求,blob存储response
	var xhr=new XMLHttpRequest();
	xhr.open('GET', url, true);
	//禁用缓存,否则会出现xls文件不更新的bug
	xhr.setRequestHeader("Cache-Control", "no-cache");
	xhr.setRequestHeader("If-Modified-Since","0");
	//指定返回类型,解决jquery的解析问题
	xhr.responseType = "blob";
	xhr.onload = function() {
		//状态200,成功返回
		if (this.status == 200) {
			var blob = this.response;
			//如果是IE,使用msSaveOrOpenBlob进行保存
			if (window.navigator.msSaveOrOpenBlob) {
				navigator.msSaveOrOpenBlob(blob, fileName+'.xls');
			}else{
				//不是IE,模拟a的点击事件
				var link=document.createElement("a");
				link.href=URL.createObjectURL(blob);
				link.style="visibility:hidden";
				link.download=fileName+".xls";
				document.body.appendChild(link);
				link.click();
				document.body.removeChild(link);	
	     	}
	     }else{
	        	alert("数据下载异常,请重试!");
	     }
	     //恢复按钮可用
		$("#export").attr("disabled",false);
	}
	xhr.send();

这里有几个注意的点:

  1. 是否禁用缓存要视需求而定,如果需要下载的文件中的数据是固定的,那么可以使用缓存。使用缓存之后,第一次请求后浏览器会缓存文件,当再次请求的时候,服务器端不再返回200,而是304,此时从缓存中获取文件(如下图,已接收只有185b,说明文件并不是从服务器返回的)。如果数据总是要求最新的,那么一定要禁用缓存。
    使用Ajax实现异步文件下载(支持IE)_第1张图片
  2. xhr.responseType = “blob”,这个指定了请求返回后的数据格式,这也是为什么jquery的ajax无法处理返回数据的原因。

好了,这是ajax实现异步下载的方法,赶紧试一试吧!

你可能感兴趣的:(前端js,异步下载,ajax,IE,异步文件下载)