8
For reference, a record of the problems encountered at ordinary times

1. Ordinary download

When the resource returned by the backend is a link, you can use the a tag or window.location.href to open it directly.

1, a label form

In H5, the a tag has a new download attribute. When a link containing this attribute is clicked, the browser will download the link on the href attribute by downloading a file.

 <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. Open window.location.href directly

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

2. Streaming file download

When the file returned by the backend is a streaming file, take the umi-request request method as an example

First, set the return type in the 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. Customize the file name

At this point, you can find that the backend returns a stream file, and the front end receives garbled characters. When you customize the file name on the front end, you can download it directly

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

2. Use the file name defined by the backend

When the back-end fileName is used, the file name defined in the content-disposition should be obtained at this time.

First call the interface and find that the file name is in the request header content-disposition . It should be noted that although we can see it, we cannot get the request header.

If you want the browser to be able to access other response headers, you need to set Access-Control-Expose-Headers

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

At this time, you can get the relevant information and find that it is encoded, and you need decodeURI to decode

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

const fileName = decodeURI(disposition.split(";")[1].split("filename=")[1])
Note: The request header information cannot be obtained directly in the request method, and the request needs to be intercepted
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;
});

The complete code is as follows:

request file

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 file

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

js file

async download() {
   await downLoadExcel('http://example.com/api/download');
},

__青春的Smile
185 声望8 粉丝