乐趣区

关于前端:文件导出

在后盾管理系统中,咱们常常会遇到文件导出这个需要,上面,我将几种常见的导出形式做一个简略的介绍,让大家在当前遇到此类需要时,可能切合实际状况,采取绝对正当的形式。

导出指标

文件地址
曾经存在服务器上的文件,比方用户上传的图片、资料等等
http://192.168.1.103:3000/imgs/bg.jpg

导出接口
依据用户需要,动静生成的文件,常见的比方导出业务流水表格,数据汇总表格等等
http://192.168.1.103:3000/api/export

导出形式

a.download

html5 新增的属性

文件名由前端指定,前台下达保留指令

毛病:ie 不反对,并且,在跨域时,即便后盾设置了容许跨域的响应头,也无奈下载,也就是说,必须与以后域统一

<a href="http://192.168.1.103:3000/imgs/xx.jpg" download />
<a href="http://192.168.1.103:3000/imgs/xx.jpg" download="xx.jpg" />

ajax + a.download

文件名由前台指定,前台下达保留指令

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

毛病:ie 不反对,blob 有内存限度

然而防止了独自应用 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 专有 api

毛病: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

文件名由后盾指定,此种形式指定的文件名优先级高于 a.download

前端发送申请即可,须要留神的一点是,不能与 ajax 组合(应用 ajax 后,会变成二进制流,须要前端对流解决)

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

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

function useLocationDownload(url) {window.location.href = url;}
useLocationDownload(url)

window.open

function useWindowOpenDownload(url) {window.open(url);
}
useWindowOpenDownload(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)
  • 一些问题

    1. 跨域

      a.download 有效,即便后盾设置了 Access-Control-Allow-Origin 也有效,download 的值须要与以后域名统一,让 ngnix 进行转发能够解决。

      https://html.spec.whatwg.org/dev/links.html#downloading-resources

    2. 大文件

      ajax 的形式须要用到 blob,而 blob 是有限度的,例如 chrome 的下限是 2GB,所以 ajax 的形式须要被排除,可选的形式是 a.download 和 Content-Disposition,这两种形式没有用到 blob,所以也没有具体的限度。

    3. 在应用 a 标签或者 form 时,为了防止在导出时产生页面闪动景象,咱们能够应用 target 非_self 的值,来防止,然而当 target 为_self 时,如果导出申请失败了,页面会被笼罩掉,用哪种形式能够防止这个问题?

      可选的形式为 ajax 和 iframe,这两者都能够防止失败时笼罩掉以后页面,并且 ajax 还能够通知用户失败的起因

  • 总结

    默认状况下,浏览器面对本身无奈关上的文件,都会采取将其保留到本地形式,然而如图片,文本文件以及 pdf,浏览器首先尝试关上,这在个别状况下是正当的,但当咱们的目标是保留而不是关上时,这就会变成一个问题。

    上文列举了几种导出形式以及各自的局限性,综合来看 Content-Disposition 应该是比拟通用的形式,即兼顾了兼容性,也防止了浏览器内存限度。

材料

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

退出移动版