前端下载非同源文件自定义文件名方案

2021-12-23  本文已影响0人  0月

背景

有时候我们需要点击下载一些资源如excel 、pdf、 ppt、图片等,并且要支持自定义下载名字。当下载链接与当前页是同源时,可以通过a标签download属性设置,比如我在a.com打开的页面下载a.pdf

<a download="自定义名字.pdf" href="a.com/a.pdf">下载</a>

这样子同源下载的文件名就是 "自定义名字.pdf"

但是一般实际场景,文件资源都是有独立的资源服务器的,和主应用的域名不一致,上面的方法就不管用了。那么也没有其他方法呢?

方案

下载的实际原理就是前端发一个http请求去目标链接,然后资源服务器在接收请求后在response header里面设置content-type为文件流,和 Content-Disposition,例如:

Content-Type: 'application/octet-stream',
Content-Disposition: 'attachment;filename=a.pdf'

然后浏览器在接收文件流时自动采用下载的方式接收,这是浏览器自动识别的,那么有没有人工手动控制这个流程呢?其实是可以的。

搞清楚整个下载流程后,我们可以得到一个解决方案:

前端可以通过ajax去请求资源链接,因为服务端返回的是文件流,前端要接收的话,就需要知道怎么去操作文件流,前端在html5之后有个Blob对象,所以我们在请求时要设置对应的responseType:blob就可以通过blob接收,最后把blob数据保存到本地。

具体操作如下:

利用现成工具,安装 axios 、file-saver

npm i axios file-saver -S

然后代码:

/**
 * URL地址下载文件
 * @param url 下载地址
 * @param fileType  excel | csv 或者不确定类型的,直接传类型,例如 bipkg
 * @param fileName 文件名称
 * @private
 */
const downloadByUrl = (url, fileType, fileName = '未命名') => {
  return axios.get(url, {
    responseType: 'blob',
    beforeErrorAction () {
      return false;
    },
  }).then(res => {
    let mime = '';
    switch (fileType) {
      case 'xlsx':
        mime = 'application/vnd.ms-excel';
        break;
      case 'csv':
        mime = 'text/csv';
        break;
      default:
        break;
    }
    const blob = new Blob([res], { type: mime });
    fileSaver.saveAs(blob, `${fileName}.${fileType}`);
  }).catch(() => {
    const aTag = document.createElement('a');
    aTag.href = url;
    aTag.download = fileName; // 此属性仅适用于同源 URL https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a
    aTag.style.display = 'none';
    document.body.appendChild(aTag);
    aTag.click();
    // 下载完成后删除dom节点
    document.body.removeChild(aTag);
  });
};

调用方法下载

downloadByUrl('xxx.com/a.pdf', 'pdf', '自定义名字')

总结

以上就是前端自定义下载文件名的解决方案,如果你有更好的方法欢迎交流。

上一篇下一篇

猜你喜欢

热点阅读