Several ways to download files on the front end

1. A tag download download The
back end returns a downloadable url file, or a file saved locally on the front end, and downloads it through the path.
(1) Put the resources into the front end for local storage, and upload them from the server after packaging
Insert picture description here

// 本地资源下载,引入路径即可,这里的路径指的是打包后文件与代码文件的相对路径
<a href="./import-template.xlsx" download target="_blank">
  下载上传模板 
</a>

(2) Request the server and put the returned url into the href attribute of the a tag.
The following is the pseudo code. The implementation steps first get the url, use it as a variable and put it into the href attribute of the a tag. Different framework methods are different.

let requestUrl = 'xxxxxx';
let responseUrl = '';
fetch(requestUrl ).then(res => {
    
    
 responseUrl = res.data.url
})

// dom节点渲染如果responseUrl出现跨域,download将失效,无法下载
<a href=`${
    
    responseUrl }` download target="_blank">
  下载上传模板 
</a>

(3) Does not rely on the framework, native js realizes the way to click and download

//点击某个按钮触发事件
 const onClickDownFile = (id) => {
    
    
let requestUrl = `xxxxxx${
    
    id}xxxx`;
fetch(requestUrl).then(res => {
    
    
	//为了解决a标签跨域无法下载的问题
	const x = new XMLHttpRequest();
      x.open('GET', res.data.url, true);
      x.responseType = 'blob';
      x.onload = () => {
    
    
        const dataurl = window.URL.createObjectURL(x.response);
        const a = document.createElement('a');
        a.href = res.data.url;
        a.download = res.data.url;
        a.click();
        a.remove();
      };
      x.send();
})
  };

2. The back-end interface returns a binary stream, and the front-end needs to receive and process

import {
    
     stringify } from 'qs';

type Method = 'GET' | 'POST';

/**
 * 下载文件
 * @param url 接口路径
 * @param data 请求的参数
 * @param method 请求方式
 * @param type 下载文件的类型
 * @param fileName 自定义文件名称
 */
export const download = (
  url: string,
  data: any,
  method: Method,
  type: string,
  fileName?: string,
) => {
    
    
  /** fetch 配置项 */
  const params: RequestInit = {
    
    
    method,
    headers: {
    
    
      Authorization: '',
      'response-type': 'arraybuffer',
    },
  };

  if (method === 'GET') {
    
    
    // 每次请求添加时间戳,避免 GET 请求遭遇 HTTP 缓存
    data._ = new Date().getTime();

    // 请求参数合并到 URL 上
    url += `?${
    
    stringify(data)}`;
  } else {
    
    
    params.body = JSON.stringify(data);
  }

  return fetch(url, params)
    .then((response) => {
    
    
      if (response.status === 200 && response.body) {
    
    
        if (!fileName) {
    
    
          const cd = response.headers.get('content-disposition');
          const cds = cd?.split('filename=') || [];
          if (cds[1]) {
    
    
            fileName = decodeURIComponent(cds[1]);
          }
        }
        return response.blob();
      }

      return Promise.reject();
    })
    .then((_blob) => {
    
    
      const blob = new Blob([_blob], {
    
    
        type,
      });
      const link = document.createElement('a');
      link.href = window.URL.createObjectURL(blob);
      link.download = fileName || 'file';
      link.click();

      return 'done';
    });
};

How to use

download(
    ’xxxx‘,
    {
    
    },
    "GET", //或者"POST"
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8',
    fileName, //文件名称
  )

type is the file type, different file types have different types

suffix MIME Type
.doc application/msword
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls application/vnd.ms-excel
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.ppt application/vnd.ms-powerpoint
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation

3. The backend returns a binary stream file as appropriate.
I encountered such a requirement in a project. The front-end imports the file, the back-end parses and returns the result. If it succeeds, the returned data is null and the code is 0. If it fails, it returns an excel binary stream file in the excel file. The reason for the failure is displayed, and the file is automatically downloaded.


const downloadBlob = (blob: Blob, type: string, fileName?: string) => {
    
    
  const newBlob = new Blob([blob], {
    
    
    type,
  });
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(newBlob);
  link.download = fileName || '错误文件';
  link.click();
};

export const FileUpload = (url: string, file: FormData): Promise => {
    
    
  /** fetch 配置项 */
  const params: RequestInit = {
    
    
    method: 'POST',
    headers: {
    
    
      Authorization: '',
    },
    body: file,
  };

  return fetch(url, params).then((response) => {
    
    
    if (response.status === 200 && response.body) {
    
    
      return new Promise((resolve, reject) => {
    
    
        const contentType = response.headers.get('content-type') || '';

        if (contentType.indexOf('application/json') >= 0) {
    
    
          // 返回的是 JSON 文件
          response.json().then(resolve);
        } else if (contentType.indexOf('application/vnd.ms-excel') >= 0) {
    
    
          // 返回的是 excel 文件
          response.blob().then((_blob) => {
    
    
            const cd = response.headers.get('content-disposition');
            const cds = cd?.split('filename=') || [];

            downloadBlob(
              _blob,
              'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8',
              decodeURIComponent(cds[1]),
            );

            resolve();
          });
        } else {
    
    
          // 暂时不知道是啥
          reject();
        }
      });
    }

    return Promise.reject();
  });
};

There are many types of
content-type , each of which corresponds to a different return type. A complete list of content-type comparisons: https://tool.oschina.net/commons/

Guess you like

Origin blog.csdn.net/glorydx/article/details/110226086