前端下载文件的几种方式


在这里插入图片描述

一、a标签download下载

后端返回一个可下载的url文件,或者前端本地保存的文件,通过路径引入下载。

(1)将资源放入前端本地保存,打包后随一起上传自服务器

在这里插入图片描述

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

(2) 请求服务器,返回的url放入a标签的href属性中,

下面是伪代码,实现的步骤 先获取url,将其作为变量,放入a标签的href属性中,不同的框架方法不同。

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

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

(3)不依赖框架,原生js实现点击下载的方式

//点击某个按钮触发事件
 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();
})
  };

二、后端接口返回二进制流,前端需要接收处理

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';
    });
};

使用方式

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

type是文件类型,不同的文件类型type不同

后缀MIME Type
.docapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.xlsapplication/vnd.ms-excel
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.pptapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation

content-type 的类型有很多种,每一种对应不同的返回类型,
content-type对照大全 : https://tool.oschina.net/commons/

三、后端视情况返回二进制流文件(特殊情况,很少遇到)

我在一个项目中遇到这样一个需求,前端导入文件,后端解析并返回结果,如果成功,返回的data为null,code为0,如果失败,返回一个excel的二进制流文件,在excel文件中显示的是失败的原因,并自动下载文件。


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();
  });
};

content-type 的类型有很多种,每一种对应不同的返回类型,
content-type对照大全 : https://tool.oschina.net/commons/

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可缺不可滥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值