关于项目上前端下载的那些事

119 阅读1分钟

今天写这篇文章是记录一下项目上之前没踩过的前端下载的坑,发出来希望大家可以给点意见或者自取其用~

一、GET下载

这种下载方式通常比较常见

1、可以使用a标签进行下载

<a href='下载文件的url' download>点我下载</a>

<a href='下载文件的url' download='文件名.(后缀名)'>点我下载</a>

href就是你要下载的地址,需要的是全路径,在后端的服务器上;

download还可以修改文件下载后的名字和类型,如果不需要修改后缀名,可不写;

2、window.open开启新tab下载

window.open('目标url')

// 携带参数
window.open(`目标url?a=111&b=${xxx}`)

该方法通过winodw.open打开新的tab,利用浏览器无法解析的资源会变成下载的特性来实现功能,api也不复杂 也可以携带参数

3、已知文件内容,通过URL.createObjectURL()下载文件

const onDownload = (url, fileName) => {
  const x = new XMLHttpRequest();
  x.open('GET', url, true);
  x.responseType = 'blob';
  // 监听进度
  x.onprogress = (e) => {
    if (e.lengthComputable) {
      // 文件总体积
      console.log('文件总体积', e.total);
      // 已下载体积
      console.log('已下载体积', e.loaded);
    }
  };
  x.onload = () => {
    const url = window.URL.createObjectURL(x.response);
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    a.click();
    a.remove();
    // 释放
    window.URL.revokeObjectURL(url);
  };
  x.send();
};

当点击下载按钮时,请求接口,返回文件流。

URL.createObjectURL()静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

createObjectURL()支持传入 File 对象、Blob 对象或者 MediaSource 对象(媒体资源)。

4、使用FileReader进行下载

/**
 * 下载文件
 * @param {String} path - 下载地址/下载请求地址。
 * @param {String} name - 下载文件的名字(考虑到兼容性问题,最好加上后缀名)
 */
 
downloadFile (path, name) {
 const xhr = new XMLHttpRequest();
    xhr.open('get', path);
    xhr.responseType = 'blob';
    xhr.send();
    xhr.onload = function () {
        if (this.status === 200 || this.status === 304) {
        const fileReader = new FileReader();
        fileReader.readAsDataURL(this.response);
        fileReader.onload = function () {
          const a = document.createElement('a');
          a.style.display = 'none';
          a.href = this.result;
          a.download = name;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
 	};
     }
   };
}
 

二、POST下载

post下载一般有2种形式,第一种通过请求接口获取一个完整的文件下载路径,然后再通过window.open()的方式进行下载;第二种后端返回的文件流,前端通过解析文件流的方式进行下载。

1、后端返回完整链接下载

这种下载方式就比较简单了,直接使用项目封装的fetch去请求接口,拿到返回结果直接使用window.open下载即可

2、文件流下载

后台返回文件流,前端解析完成之后下载

下载csv格式

/* eslint-disable comma-dangle */
/* eslint-disable arrow-parens */
import moment from 'moment';

// 接口返回文件流,前端进行处理
export function downloadFromFileBuffer(
  fileType = 'application/csv',
  fileEncode = 'Unicode(UTF-8)',
  fileName = `${moment().format('YYYYMMDDHHmmss')}.csv`,
  content,
) {
  const blob = new Blob([fileType === 'application/csv' ? `\uFEFF${content}` : content], {
    type: `${fileType};charset=${fileEncode}`,
  });
  const a = document.createElement('a');
  const URL = window.URL || window.webkitURL;
  const herf = URL.createObjectURL(blob);
  a.href = herf;
  a.download = fileName;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  window.URL.revokeObjectURL(herf);
}




// 请求接口内容
request(
  '/api',
  {
    method: 'POST',
    body: params,
  },
  false,
  true,
).then((ret) => {
  downloadFromFileBuffer('application/csv', 'Unicode(UTF-8)', `终端安全事件-${moment().format('YYYYMMDDHHmmss')}.csv`, ret);
}).finally(() => {
  setSubmitting(false);
});

下载xlsx格式

fetch(`/api`, {
  method: 'POST',
  body: JSON.stringify(params),
  headers: {
    ...setCommonHeader({}),
    responseType:'blob', // 重要,一定要写,不然乱码无法解析导致文件损坏无法打开
    'Content-type': 'application/json;charset=UTF-8',
    Authorization: localStorage.getItem('token'),
  }
})
  .then((res) => res.blob())
  .then((data) => {
    const blobUrl = window.URL.createObjectURL(data);
    const a = document.createElement('a');
    a.download = `威胁狩猎-${moment().format('YYYYMMDDHHmmss')}.${type}`;
    a.href = blobUrl;
    a.click();
  });