使用a标签下载文件,浏览器会直接打开?如何解决

642 阅读1分钟

文件下载是很多项目中的常见需求,实现方式通常是使用 a 标签实现:

<a href="url" download='filename'>下载</a>

在这种情况下,不支持跨域的链接,我们一般会用下面这种方式。

export function getUrlBlob(url: string): Promise<{ blobData: Blob; url: string }> {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'blob';
  return new Promise((resolve, reject) => {
    xhr.onerror = reject;

    xhr.onload = function () {
      const blob = this.response;
      const blobData = new Blob([blob]);
      resolve({
        blobData,
        url: window.URL.createObjectURL(blobData),
      });
    };

    xhr.send();
  });
}

export const exportDownload = async (url: string,filename:string) => {

  let a = document.createElement('a');
    a.href = (await getUrlBlob(url)).url;
    a.download = filename;
    a.click();
    a.remove();

};

这中方法很常见,把资源下载到浏览器,在转成blob,生成一个临时的URL,这样就不会有跨域问题,但是这种情况会有个严重的问题,当文件比较大时就会很麻烦。

解决办法

  1. download参数
  const urlObj = new URL(addHttpsToUrl(url));
  urlObj.searchParams.set('download', filename);
  a.href = urlObj.toString()
  a.click();
  window.URL.revokeObjectURL(a.href);
  a.remove();

这种情况下载时,服务器可以根据download参数的值来设置下载的文件名为filename。 请注意,这个功能的可用性取决于服务器的实现。不是所有的服务器都支持这种方式来指定下载文件名。 2. response-content-type=application/octet-stream

  const urlObj = new URL(addHttpsToUrl(url));
  urlObj.searchParams.set('response-content-type=application', 'octet-stream');
  a.href = urlObj.toString()
  a.click();
  window.URL.revokeObjectURL(a.href);
  a.remove();

这种情况也可以下载,但是不支持自定义name