【JS】前端文件下载(无刷新)方法总结
#传统方法
利用iframe 或 form.submit 或 windows.open直接向后端发请求,后端返回文件流,后端处理成功后会直接返回到页面,浏览器会整理并打开自己的保存下载文件机制 。
1、利用form.submit直接向后端提交,后端返回文件流
1)前端代码:
var downloadURL = "RestHandle.ashx";
var testForm = $("<form>"); //定义一个form表单
testForm.attr('style','display:none'); //设置form表单属性
testForm.attr('target','');
testForm.attr('method','post');
testForm.attr('action',downloadURL); var nameInput = $('<input>'); //构造formdata
nameInput.attr('type','hidden');
nameInput.attr('name','fileName');
nameInput.attr('value','test.txt'); $('body').append(testForm); //将表单放置在web中
testForm.append(nameInput); //将formdata添加到表单上
testForm.submit(); //表单提交
testForm.remove(); //表单移除
2)服务端代码,以asp.net为例:
public class TestHandler : IHttpHandler
{ public void ProcessRequest(HttpContext context)
{
string fileName = context.Request["FileName"];//客户端传送过来的要下载的文件名
string filePath = System.Web.HttpContext.Current.Server.MapPath("DownLoad/" + fileName);//路径 FileInfo newFile = new FileInfo(filePath); //以字符流的形式下载文件
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, , bytes.Length);
fs.Close();
context.Response.ContentType = "application/octet-stream";
//通知浏览器下载文件而不是打开
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8));
context.Response.BinaryWrite(bytes);
context.Response.Flush();
context.Response.End();
} public bool IsReusable
{
get
{
return false;
}
}
}
3)优缺点:
优点 :兼容性良好,传统方式,不会出现URL长度限制问题;
缺点:拿不到后端处理这个过程的时机,无法根据回调函数做交互以及进度提示
2、利于iframe直接向后端提交,后端返回文件流
1)前端代码:
function downFileByIframe(parameters) {
var downloadURL = "TestHandler.ashx?FileName=test.txt";
var iframe = document.createElement("iframe");
iframe.src = downloadURL;
iframe.style.display = "none";
document.body.appendChild(iframe);
}
2)后端代码:同上
3)优缺点:
优点: 兼容性较好
缺点: *html中会增加多余的iframe元素,增加了维护成本;
*拿不到后端处理这个过程的时机,无法根据回调函数做交互以及进度提示;
*URL长度有限制;
3、使用windows.open下载文件
1)前端代码
var downloadURL = "TestHandler.ashx?FileName=test.txt";
window.open(downloadURL);
2)后端代码:同上
3)优缺点:
优点: 兼容性良好,代码简洁;
缺点: *URL长度有限制;
*拿不到后端处理这个过程的时机,无法根据回调函数做交互以及进度提示;
4、解决“无法根据回调函数做交互”的问题:ajax提交,后端返回在线文件地址
利用ajax去提交请求,后端会返回一个线上的文件地址,前端可以通过原生的window.open打开这个地址就可以实现下载;
也可以通过a标签设置href以及download属性,并自动点击实现其下载功能,关于其兼容性问题,可以判断download属性是否存在来弥补。
1)优缺点:
优点 :可以拿到其返回时机,可以做交互;
缺点 :线上产生大量的中间临时文件,可以用设置时限来优化。解决方案:可使用大厂的云存储,从而减少临时文件的产生;
2)前端代码:
$.ajax({
type: "post",
url: "TestHandler.ashx",
data: {'FileName':'test.txt'},
success: function (res) {
if (res.Status) {
// window.open或者a标签下载
var isSupportDownload = 'download' in document.createElement('a');
if (isSupportDownload) {
var $a = $("<a>");
$a.attr({
href: res.url,
download: 'filename'
}).hide().appendTo($("body"))[0].click();
} else {
window.open(res.url)
}
} else {
alert(res.Message);
}
}
})
5、解决“无法根据回调函数做交互”的问题:jquery-download 插件
jquery.download.js插件github地址:https://github.com/johnculviner/jquery.fileDownload/blob/master/src/Scripts/jquery.fileDownload.js
jquery.download.js插件cdn地址:https://www.bootcdn.cn/jquery.fileDownload/
支持场景 : 与上面的几种方案相比,这个模块提供的方案更加完善,而不是局限于某种方案,相当于将上面的几种方案结合了起来, 使用率很高。在源码中,我们可以看到在这个模块中针对各个浏览器和相应的属性是否支持进行了比较全面的兼容。其对应的下载文件方案包括了以下几种。
- window.open(url)打开某个文件地址
- iframe的框架中,设置src属性,通过iframe进行文件的下载,支持文件地址
- 通过form标签,设置action的文件地址,然后通过form的提交来完成文件的下载
1)前端代码:
var downloadURL = "TestHandler.ashx";
$.fileDownload(downloadURL, {
httpMethod: 'post',
data: { 'FileName': 'test.txt' },
prepareCallback: function (url) {
console.log("文件下载中...");
// 数据加载动画
$("body").append('<div id="Loading" style="background:url(images/load.png) top center no-repeat;"></div>');
},
abortCallback: function (url) {
// 异常终止
console.log("文件下载异常!!");
$("#Loading").remove();
},
successCallback: function (url) {
console.log("文件下载成功!!");
$("#Loading").remove();
},
failCallback: function (html, url) {
console.log("文件下载失败!!");
$("#Loading").remove();
}
});
2)后端代码:
public void ProcessRequest(HttpContext context)
{
string fileName = context.Request["FileName"];//客户端保存的文件名
string filePath = System.Web.HttpContext.Current.Server.MapPath("DownLoad/" + fileName);//路径 FileInfo newFile = new FileInfo(filePath); //以字符流的形式下载文件
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] bytes = new byte[(int)fs.Length];
fs.Read(bytes, , bytes.Length);
fs.Close(); context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8));
context.Response.BinaryWrite(bytes); //该cookie用于告诉jquery.fileDownload.js文件下载成功
context.Response.Cookies.Add(new HttpCookie("fileDownload", "true"));
context.Response.Flush();
context.Response.End();
}
注意: 这里的后端代码增加了一个名为“fileDownload”的cookie的返回;jquery.download.js插件使用该cookie来判断是否下载成功,从而进入成功回调函数(successCallback);
#新兴方案
1、利用Html5的download属性进行下载
1)前端代码
<a href="TestHandler.ashx?FileName=test.txt" download="test1.txt">DownloadAttrTest</a>
2)后端代码:同上
3)优缺点:
优点:代码简洁
缺点:存在浏览器兼容性的问题
4)参考:
https://www.zhangxinxu.com/wordpress/2016/04/know-about-html-download-attribute/
2、利用Html5的Blob对象实现对文件流进行下载
(1)、 使用原生js发送ajax实现
1)前端代码:
function downByBlob_1(parameters) {
var downloadURL = "TestHandler.ashx?FileName=zip.rar";
let xhr = new XMLHttpRequest()
let fileName = 'zip.rar' // 文件名称
xhr.open('GET', downloadURL, true);
xhr.responseType = 'arraybuffer';
//xhr.setRequestHeader('xx', 'xxxxx') // 请求头中添加信息
xhr.onload = function () {
if (this.status === 200) {
let type = xhr.getResponseHeader('Content-Type')
let blob = new Blob([this.response], { type: type })
if (typeof window.navigator.msSaveBlob !== 'undefined') {
/*
* IE workaround for "HTML7007: One or more blob URLs were revoked by closing
* the blob for which they were created. These URLs will no longer resolve as
* the data backing the URL has been freed."
*/
window.navigator.msSaveBlob(blob, fileName);
} else {
let URL = window.URL || window.webkitURL;
let objectUrl = URL.createObjectURL(blob);
console.log(objectUrl);
//"blob:http://localhost:10614/3e48b856-fca6-4e4c-b780-1c4a7066f42e"
if (fileName) {
var a = document.createElement('a');
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = objectUrl
} else {
a.href = objectUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
a.remove();
}
} else {
window.location = objectUrl;
}
}
}
}
xhr.send();
}
2)后端代码:同上
(2)、 使用结合jq发送ajax请求实现,需要引入jquery.binarytransport.js插件,其扩展了jq的ajax的dataType的设置;
jquery.binarytransport.js插件github地址:https://github.com/henrya/js-jquery/tree/master/BinaryTransport
注意:当下载的是纯文本文件时,是不需要引入插件,ajax也不用配置dataType,直接用jq的ajax即可;
1)前端代码:
function downByBlob_2(parameters) {
$.ajax({
type: "post",
url: "TestHandler.ashx",
data: { 'FileName': 'zip.rar' },
dataType: 'binary',
responseType: 'arraybuffer',
success: function (msg) {
let blob = new Blob([msg]);
console.log("Blob:" + msg); //msg 已不是乱码
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = 'zip.rar'; //命名下载名称
a.click(); //点击触发下载
window.URL.revokeObjectURL(url); //下载完成进行释放
}
});
}
2)后端代码:同上
3)参考:
http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
https://blog.csdn.net/aydongzhiping/article/details/82462473
3、新兴方案中的综合方案:file-saver
(1)、FileSaver.js 功能特点
- FileSaver.js 是一款基于 HTML5 完成文件保存的插件,它可以帮我们直接从网页中导出多种格式文件。
- 同时对于那些本身不支持 HTML5 W3C saveAs() FileSaver 接口的浏览器,FileSaver.js 也提供了支持。
- 使用 FileSaver.js 可以让 Web 应用完美的生成文件,或者保存那些不应该发送到外部服务器的敏感信息。是一种简单易用的浏览器端文件保存方案。
(2)、安装
FileSaver.js github地址:https://github.com/eligrey/FileSaver.js
可直接下载 FileSaver.js 然后在页面中引用;
npm、bower 安装:
npm install file-saver --save
bower install file-saver
(3)、demo:使用 FileSaver.js下载后端返回的文件流;
1)前端代码:
function downByFileSaver(parameters) {
saveAs('TestHandler.ashx?FileName=zip.rar');
}
2)后端代码:同上
4、新兴方案的优缺点:
优点:技术新颖,某些场景下使用方便;
缺点:兼容性不好;
#参考
https://juejin.im/post/5bd5547a6fb9a05cdd2d5109
https://juejin.im/post/5bd1b0aa6fb9a05d2c43f004
https://www.cnblogs.com/yunser/p/7629399.html
https://blog.csdn.net/wt346326775/article/details/83617663
————————————————————————————————————————————————————
【JS】前端文件下载(无刷新)方法总结的更多相关文章
- SpringMVC结合ajaxfileupload.js实现文件无刷新上传
直接看代码吧,注释都在里面 首先是web.xml <?xml version="1.0" encoding="UTF-8"?> <web-ap ...
- js前端读写文件的方法(json、excel)
1.前端读取文件的实现 关键:利用文件上传对话框预览本地文件.利用FileReader读取文件 前端预览本地文件 <input tabindex="-1" id=" ...
- 无刷新分页 jquery.pagination.js
无刷新分页 jquery.pagination.js 采用Jquery无刷新分页插件jquery.pagination.js实现无刷新分页效果 1.插件参数列表 http://www.dtan.so ...
- ajax实现无刷新分页效果
基于jquery.pagination.js实现的无刷新加载分页数据效果. 简介与说明 * 该插件为Ajax分页插件,一次性加载数据,故分页切换时无刷新与延迟.如果数据量较大,加载会比较慢. * 分页 ...
- SpringMVC ajax技术无刷新文件上传下载删除示例
参考 Spring MVC中上传文件实例 SpringMVC结合ajaxfileupload.js实现ajax无刷新文件上传 Spring MVC 文件上传下载 (FileOperateUtil.ja ...
- ASP.NET工作笔记之一:图片上传预览及无刷新上传
转自:http://www.cnblogs.com/sibiyellow/archive/2012/04/27/jqueryformjs.html 最近项目里面涉及到无刷新上传图片的功能,其实也就是上 ...
- js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符
js中对arry数组的各种操作小结 最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...
- js实现无刷新表单提交文件,将ajax请求转换为form请求方法
最近在做项目的时候遇到一个需要上传文件的需求,因为ajax请求是无法上传二进制文件流的,所以只能用form表单提交,而form提交有一个问题就是会使页面刷新,本文解决了form表单提交文件时页面刷新的 ...
- 前台JS(Jquery)调用后台方法 无刷新级联菜单示例
前台用AJAX直接调用后台方法,老有人发帖提问,没事做个示例 下面是做的一个前台用JQUERY,AJAX调用后台方法做的无刷新级联菜单 http://www.dtan.so CasMenu.aspx页 ...
随机推荐
- 大整数相乘问题总结以及Java实现
最近在跟coursera上斯坦福大学的算法专项课,其中开篇提到了两个整数相乘的问题,其中最简单的方法就是模拟我们小学的整数乘法,可想而知这不是比较好的算法,这门课可以说非常棒,带领我们不断探索更优的算 ...
- jquery 同步加载
jquery在前端展示时,如果需要从服务器获取信息然后在更新,需要设置同步加载. async属性设置为:false即可. $.ajax({ url : 'test.php', type : 'post ...
- redis -hash(哈希.对象)
hash 用于储存对象,对象的结构为属性.值 值的类型string 增加.修改: 设置单个属性: hset 键 field 值 例如: 设置键 user 的属性name 为 python hset u ...
- WPF软件开发系统之四——医疗病人信息管理系统
仿360悬浮窗的方式,始终有个工具栏浮在桌面的最顶层,方便任何时候操作. 主要功能包括:病人信息的添加.修改.查询.包括别人基本信息.诊断结果.接待医生.手术多张图片等. 系统特点:简洁.易操作.美观 ...
- mysql的进阶
老师的博客:http://www.cnblogs.com/wupeiqi/articles/5713323.html 总结 导出与导入 导出:mysqldump -u root -p 数据库 > ...
- 试试Linux下的ip命令,ifconfig已经过时了
linux的ip命令和ifconfig类似,但前者功能更强大,并旨在取代后者.使用ip命令,只需一个命令,你就能很轻松地执行一些网络管理任务.ifconfig是net-tools中已被废弃使用的一个命 ...
- 012_python在shell下单行执行多行代码
一.有时候只是简单的获取下时间戳,不想在python解释器的交互模式下再去执行python代码,如何实现呢? 以循环输出多行为例: (1)第一种方式: python -c "exec(\&q ...
- EntityFramework Core进行读写分离最佳实践方式,了解一下(二)?
前言 写过上一篇关于EF Core中读写分离最佳实践方式后,虽然在一定程度上改善了问题,但是在评论中有的指出更换到从数据库,那么接下来要进行插入此时又要切换到主数据库,同时有的指出是否可以进行底层无感 ...
- 基于nodejs的流水线式的CRUD服务。依赖注入可以支持插件。
写代码好多年了,发现大家的思路都是写代码.写代码.写代码,还弄了个称号——码农. 我是挺无语的,我的思路是——不写代码.不写代码.不写代码! 无聊的代码为啥要重复写呢?甚至一写写好几年. 举个例子吧, ...
- 三十九、vue中element最原始的分页(未封装的)
html<el-table ref="scoreUserTable" :data="scorePageUser.slice((currentPage1-1)*pag ...