乐趣区

关于前端:js下载文件的实现方式

供参考,平时遇到的问题记录

一、一般下载

当后端返回的资源是链接时,此时能够应用 a 标签或者 window.location.href间接关上。

1、a 标签模式

在 H5 中,a标签新增了download 属性,蕴含该属性的链接被点击时,浏览器会以下载文件形式下载 href 属性上的链接。

 <a href="https://example.com" download="example.html"> 下载 </a>

// 或者封装
function download(href, title) {const a = document.createElement('a');
    a.setAttribute('href', href);
    a.setAttribute('download', title);
    a.click();}
download('https://example.com', 'test')

2、window.location.href 间接关上

window.location.href === 'https://example.com'

二、流文件下载

当后端返回的文件是流文件时,以 umi-request 申请办法为例

首先应在申请中设置返回类型:responseType: "blob"

import request from "umi-request";

export const downLoad = (url, fileName) =>
  request(url, {
    method: "POST",
    data: data,
    responseType: "blob", // 代表内存之中的一段为二进制
  }).then(data) => {
    const blob = data;
    let link = document.createElement("a");
    link.href = URL.createObjectURL(new Blob([blob], {type: "application/vnd.ms-excel"}) );
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    URL.revokeObjectURL(link.href);
};

1、自定义文件名

此时能够发现后端返回的是流文件,前端接到的是乱码。以后端自定义文件名时,能够间接下载

downLoad('https://example.com/api/download', 'test.xlsx')

2、采纳后端定义的文件名

当采纳后端的 fileName 时,此时要获取后端在 content-disposition 中定义的文件名。

首先调用接口,发现文件名是在申请头content-disposition 中,须要留神的是:尽管咱们能看到,然而却拿不到申请头。

如果想让浏览器能拜访到其余响应头的话,须要后端在服务器上设置 Access-Control-Expose-Headers

// 后端面大抵写法
headers.add("Access-Control-Expose-Headers", "Content-Disposition"); 

此时能够拿到相干信息,发现是编码的,须要 decodeURI 进行解码

const disposition = response.headers.get('Content-Disposition');

const fileName = decodeURI(disposition.split(";")[1].split("filename=")[1])

注:间接在申请办法里是不能获取到申请头信息的,须要对申请进行拦挡

request.interceptors.response.use(async (response) => {const disposition = response.headers.get("Content-Disposition"); // 获取 Content-Disposition
  return disposition // 当 Content-Disposition 中有值的时候进行解决,其余申请的响应则放过
    ? {blob: await response.blob(), // 将二进制的数据转为 blob 对象,这一步是异步的因而应用 async/await
        fileName: decodeURI(disposition.split(";")[1].split("filename=")[1]), // 解决 Content-Disposition,获取 header 中的文件名
      }
    : response;
});

残缺的代码如下:

request 文件

import request from "umi-request";

// 响应拦挡
request.interceptors.response.use(async (response) => {const disposition = response.headers.get("Content-Disposition"); // 获取 Content-Disposition
  return disposition // 当 Content-Disposition 中有值的时候进行解决,其余申请的响应则放过
    ? {blob: await response.blob(), // 将二进制的数据转为 blob 对象,这一步是异步的因而应用 async/await
        fileName: decodeURI(disposition.split(";")[1].split("filename=")[1]), // 解决 Content-Disposition,获取 header 中的文件名
      }
    : response;
});

export const downLoadExcel = (url) =>
  request(url, {
    method: "POST",
    data: data,
    // responseType: "blob", // 正文掉这一段
  }).then(data => {const { blob, fileName} = response;
    let link = document.createElement("a");
    link.href = URL.createObjectURL(new Blob([blob], {type: "application/vnd.ms-excel"}) );
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    URL.revokeObjectURL(link.href);
    document.body.removeChild(link);
});

react 文件

<Buttton onClick={download}> 下载 </Button>

js 文件

async download() {await downLoadExcel('http://example.com/api/download');
},
退出移动版