烹羊宰牛且为乐,会|

园龄:粉丝:关注:

前端实现文件导出

在后台管理系统中,我们经常会遇到文件导出这个需求,下面,我将几种常见的导出方式做一个简单的介绍,让大家在以后遇到此类需求时,能够切合实际情况,采取相对合理的方式。

导出目标

文件地址
已经存在服务器上的静态文件,比如用户上传的图片、材料等等。
http://192.168.1.103:3000/imgs/bg.jpg

导出接口
根据用户需求,由后端动态生成的文件,常见的比如导出业务流水表格,数据汇总表格等等。
http://192.168.1.103:3000/api/export

导出方式

image.png

a.download

html5新增的属性

优点:简单。
缺点:ie不支持,并且在跨域时,即使后台设置了允许跨域的响应头,也无法下载,也就是说必须与当前域一致。

// 这里的http://192.168.1.103:3000必须与当前地址栏一致才行
<a href="http://192.168.1.103:3000/imgs/xx.jpg" download />

download属性可以指定文件名(如果content-disposition指定了文件名,以content-disposition为准),也可以为空值,两种情况具体如下:
image.png

ajax + a.download

缺点:ie不支持,blob有内存限制。
优点:避免了单独使用a.download必须与域名一致的问题。

将后台返回的二进制数据,转换成blob,然后利用URL.createObjectURL,创建一个指向内存中blobURL,再使用a标签的download属性进行导出

function useLinkDownload(url, fileName) {
    const link = document.createElement("a");

    link.style.display = "none";
    link.href = url;
    link.download = fileName;

    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' })
    .then(function(res) {
        // 创建一个指向内存中blob的URL
        const objectURL = URL.createObjectURL(res.data);
        useLinkDownload(objectURL, 'xx.xlsx')
        URL.revokeObjectURL(objectURL)
    })

ajax + msSaveBlob

优点:支持ie,这算优点?
缺点:chrome、firefox不支持,blob有内存限制

$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' })
    .then(function(res) {
        navigator.msSaveBlob(res.data, "xx.xlsx");
    })

content-disposition

优点:兼容性极好。
缺点:需要后台支持。

前端发送请求即可(其他的交给后台),后台响应数据时,按照规范设置content-disposition,需要注意的一点是,不能与ajax组合(使用ajax后,会变成二进制数据流,流的处理被ajax接管)
(此种方式指定的文件名优先级高于a.download

var url = 'http://192.168.1.103:3000/api/export'

content-disposition可以结合以下任一一种方式进行导出:

// a标签

function useLink(url) {
  const link = document.createElement("a");

  link.style.display = "none";
  link.href = url;

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

useLink(url)
// location.href

window.location.href = url;
// window.open

window.open(url);
// form

function useFormDownload(url) {
  const form = document.createElement("form");

  form.action = url;
  form.method = "get";
  form.style.display = "none";

  document.body.appendChild(form);

  form.submit();
  form.remove();
}

useFormDownload(url)
// iframe
function useIframeDownload(url) {
  const iframe = document.createElement("iframe");

  iframe.src = url;
  iframe.style.display = "none";

  document.body.appendChild(iframe);
  document.body.removeChild(iframe);
}
useIframeDownload(url)

问题

跨域
a.download无效,即使后台设置了Access-Control-Allow-Origin也无效,download的值需要与当前域名一致,ngnix进行转发可以解决。
https://html.spec.whatwg.org/dev/links.html#downloading-resources

大文件
ajax的方式需要用到blob,而blob是有限制的,例如chrome的上限是2GB,所以ajax的方式需要被排除,可选的方式是a.downloadContent-Disposition,这两种方式没有用到blob,所以也没有明确的限制。

iframe存在的问题
在使用a标签或者form时,为了避免在导出时发生页面闪烁现象,我们可以使用targe_self的值来避免,但是当target_self时,如果导出请求失败了,页面会被覆盖掉,用哪种方式可以避免这个问题?
可选的方式为ajaxiframe,这两者都可以避免失败时覆盖掉当前页面,并且ajax还可以告诉用户失败的原因

总结

默认情况下,浏览器面对自身无法打开的文件,都会采取将其保存到本地方式,但是图片、文本文件以及pdf,浏览器会首先尝试将其打开,这在一般情况下是合理的,但当我们的目的是保存而不是打开时,这就会变成一个问题。

上文罗列了几种导出方式以及各自的局限性,综合来看Content-Disposition应该是比较通用的方式,即兼顾了兼容性,也避免了浏览器内存限制。

资料

https://github.com/eligrey/FileSaver.js/wiki/Saving-a-remote-file#using-http-header

原文链接:javascript - 文件导出 - 这好像无法拒绝 - SegmentFault 思否

本文作者:wyl-1113

本文链接:https://www.cnblogs.com/wyl-1113/p/18371558

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   #人生苦短  阅读(71)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.