关于前端a标签下载,跨域下载重命名无效问题

问题描述:在项目中写了个文件流形式的公共下载函数,但是发现下载大文件时,出现了“假死”现象,点击下载之后半天没反应,于是又改成a标签点击链接下载,但是遇到跨域文件无法重命名问题。

js文件下载大体分为两种:

一、将文件以文件流形式下载到浏览器

将文件以文件流形式下载浏览器之后,再以此文件流为a标签中的href,模拟点击下载。

缺点:

  1. 这种方式下载小文件没有啥大问题,但是如果下载大文件,就会出现用户点击之后,浏览器半天没有反应,直到文件下载完成,浏览器才会显示文件下载完成(因为是将文件流下载完成之后,才模拟一个a标签,点击下载),用户则可能认为点击无效,则多次点击下载,导致下载很多个文件,给用户体验不好。
  2. 如果文件足够大,比方说十几G的文件下载,则可能会导致浏览器崩溃,因为文件流可能超出了内存。这个只是个人推测,没有实际测试。

网上已有大量该下载代码,这里贴一个网上的代码:

/**
 * 文件下载重命名,根据依赖file-saver改写
 */
/**
 * 获取 blob
 * @param  {String} url 目标文件地址
 * @return {cb}
 */
export function getBlob(url, cb) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onload = function () {
    if (xhr.status === 200) {
      cb(xhr.response);
    }
  };
  xhr.send();
}

/**
 * 保存
 * @param  {Blob} blob
 * @param  {String} filename 想要保存的文件名称
 */
export function saveAs(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename);
  } else {
    var link = document.createElement("a");
    var body = document.querySelector("body");

    link.href = window.URL.createObjectURL(blob);
    link.download = filename;

    // fix Firefox
    link.style.display = "none";
    body.appendChild(link);

    link.click();
    body.removeChild(link);

    window.URL.revokeObjectURL(link.href);
  }
}

/**
 * 下载
 * @param  {String} url 目标文件地址
 * @param  {String} filename 想要保存的文件名称
 */
export function renameDownload(url, filename) {
  getBlob(url, function (blob) {
	 saveAs(blob, filename);
  });
}

二、直接模拟a标签点击下载

a标签点击链接下载。

缺点:

  1. 会出现跨域点击下载文件命名失效;
  2. txt,图片,pdf等文件格式浏览器直接打开,而不是下载问题。

解决方案:
但是这些问题可以通过添加header来解决,但具体是否所有浏览器都兼容,以及安全问题,本人没有深究。
下边贴代码:

/**
 * 下载
 * @param  {String} fileUrl 目标文件地址
 * @param  {String} filename 想要保存的文件名称
 */
export function renameDownload(fileUrl, fileName) {
  let link = document.createElement("a");
  //这里属性涉及到跨域问题后,设置无效
  //link.download = fileName;
  link.style.display = "none";
  //response-content-type=application/octet-stream,这里是为了防止图片,pdf,txt文件直接被浏览器打开
  //response-content-disposition的设置,解决跨域文件名重命名无效问题,encodeURIComponent防止文件名带特殊字符(例如&等)导致下载文件名出问题
  link.href =
    fileUrl +
    "?response-content-type=application/octet-stream&response-content-disposition=filename=" +
    ${encodeURIComponent(fileName)};
  document.body.appendChild(link);
  link.click();
  URL.revokeObjectURL(link.href);
  document.body.removeChild(link, fileName);
}

你可能感兴趣的:(js,前端,javascript,开发语言)