前端文件下载方式总结
写在前面:网上关于前端实现文件下载的文章已经有很多了,而且有的写的十分详细专业。之前一直不愿意做此类记录,一来是觉得这方面的文章太多太详细了,没有写的必要;二来是想着自己写的还不一定有别人写的好。但随着日常开发中用到的文件下载功能用的越多,各种下载方式都有使用过,觉得需要记录一下,以方便使用。
1、form 表单下载
1.1、表单下载基本使用
form 表单下载是比较传统的下载方式,话不多说,直接看实例:
function formDownload(data){ // data : form 表单的传参 let form = document.createElement('form'); form.id = 'idForm'; form.name = 'name_form'; form.style.display = 'none'; document.body.appendChild(form); for (let i in data) { if (i !== 'action') { let input = document.createElement('input'); //创建 input 标签并传入 form 中,作为 form 的表单的发送参数 input.type = 'text'; input.name = i; input.value = data[i]; form.appendChild(input); } else { continue; } } form.method = 'get'; form.action = URL; // form 表单发送的地址 form.submit(); document.body.removeChild(form); }
- 表单的提交就相当于一次请求,input 中的值相当于传参
- form 上有一个属性 target,这个属性指定返回结果放的位置,默认 _self 表示本页面
- 浏览器可以识别的文件不能下载:txt、png、jpg、gif等
- 无法获取下载进度
- 可以避免URL过长问题
1.2、 表单下载通过 iframe 接收返回信息并实现无刷新
将 form.target 设置成 iframe ,可以获取返回的信息,完整代码:
function formDownload(data) { // data : form 表单的传参 var target = 'sub_frame' + Date.parse(new Date()); var iframe = document.createElement('iframe'); iframe.src = window.location.href; iframe.name = target; iframe.id = target; iframe.width = 0; iframe.height = 0; iframe.style.display = 'none' document.body.appendChild(iframe); let form = document.createElement('form'); form.id = 'idForm'; form.name = 'name_form'; form.setAttribute("target", target); form.style.display = 'none'; document.body.appendChild(form); for (let i in data) { if (i !== 'action') { let input = document.createElement('input'); //创建 input 标签并传入 form 中,作为 form 的表单的发送参数 input.type = 'text'; input.name = i; input.value = data[i]; form.appendChild(input); } else { continue; } } form.method = 'get'; form.action = URL; // form 表单发送的地址 form.submit(); document.body.removeChild(form); // 通过循环去拿返回数据 var count = 0; var timer = setInterval(function () { var iframeObj = $(window.frames[target].document); var val = iframeObj.find("pre").text(); count++; if (count >= 60) { window.clearInterval(timer); document.body.removeChild(iframe); return false } if (val) { var res = JSON.parse(val); window.clearInterval(timer); document.body.removeChild(iframe); } }, 1000) }
2、直接跳转下载
2.1、location.href
window.location.href = url;
2.2、window.open
window.open(url);
- 以上两种适合 get 请求的单文件下载
- 会出现 url 过长的问题,需要注意 url 编码
- 浏览器可以识别的文件不能下载:txt、png、jpg、gif等
3、a链接下载
let a = document.createElement('a'); a.style = 'display: none'; a.download = filename; a.href = url; document.body.appendChild(a); a.click(); // 触发a标签的click事件 document.body.removeChild(a);
这种方式也无法解决浏览器可识别文件直接打开的问题,但是 HTML5 新属性 download 属性会解决这个问题。
但是也会有局限:部分情况下会出现跨域问题,此时还是浏览器预览而非下载,download属性失效。可以用这个方法试一下文本、图片。
部分浏览器由于兼容性问题(一般不会出现):
const isSupport = 'download' in document.createElement('a');
看支不支持 download 属性
4、文件流下载之 blob + a 链接 + blob URL
let xhr = new XMLHttpRequest(); xhr.open('GET', videoUrl, true); xhr.responseType = 'blob'; xhr.onload = function() { if (xhr.status === 200) { // 将视频Blob对象创建一个临时URL let videoBlob = xhr.response; let url = window.URL.createObjectURL(videoBlob); // 设置a标签的属性,并触发点击事件进行下载 a.href = url; a.download = fileName; //文件名 a.click(); // 释放URL对象 window.URL.revokeObjectURL(url); a.remove() } }; xhr.send();
发送 http 请求,指定返回值类型是 blob 流
建议加上 download 的后缀名,避免极个别浏览器无法识别
这种实现本质是通过 blob URL方式
可通过 xhr.getResponseHeader("Content-Disposition") 获取 header 上的 Content-Disposition 属性,通过截取得到文件名
5、 文件流下载之 blob + a 链接 + readAsDataURL
let xhr = new XMLHttpRequest(); xhr.open('GET', videoUrl, true); xhr.responseType = 'blob'; xhr.onload = function() { if (xhr.status === 200) { // 将视频Blob对象创建一个临时URL let videoBlob = xhr.response; const fileReader = new FileReader(); fileReader.readAsDataURL(videoBlob); fileReader.onload = function () { const a = document.createElement('a'); a.style.display = 'none'; // 结果本质上是 base64 编码的 data URL 格式 a.href = fileReader.result; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); } } }; xhr.send();
这个方法和上个 方法都是获取 blob 形式的返回值,只是结果处理方式不同,这种方式是通过 readAsDataURL 生成 base64 编码的 Data URL 再通过连接下载。
两种方法都可以解决 浏览器直接打开无法下载的问题