前端文件下载的方式

方式一:a标签直接下载

<a href="链接" >下载</a>

一个文件链接(一般是服务器上的某个文件),这个链接一般地址栏输入是预览,不是附件下载

如果想改成附件下载,以下两种方式任选一个均可:
1、后端处理,后端加上一个响应头

res.setHeader('Content-Dispostion', 'attachment', 'name.pdf')

2、a标签 加上 download属性

<a href="链接" download="文件名" >下载</a>

方式一的缺点:

缺点:在 JavaScript 中使用 a 标签下载文件时,直接通过 a标签的点击事件触发浏览器下载,是无法设置请求头的,因为这是一个简单的 GET 请求。如果这个文件的下载要求的是携带token,那a标签这种就不生效了(a标签没法携带token),会成为预览。
方案:a标签可以携带cookie,所以可以有另一种解决方法,在下载文件前,发送一个请求获取一个临时token通过cookie进行携带,a标签下载是流式下载,会把服务器的文件像流水一样存储到本地磁盘,所以下载直接能看到下载,不会将文件缓存到浏览器。

标题方式二:使用 XMLHttpRequest 或 Fetch API 请求。

写一个方法进行下载 (本质还是利用a标签进行下载)
这个方法可以是一个ajax请求,这个请求就可以携带token,然后将请求到的服务器文件转成blob,在创建一个a标签进行下载,创建虚拟的链接元素,模拟点击下载。该方法会占用前端线程。


import fetch from 'isomorphic-fetch';
const exportFile = (url, options) => {
  const projectId = sessionStorage.getItem(PROJECT_ID);
  const downLoadURL = projectId ? BATCH_ACTION_URL_PREFIX.V2 : BATCH_ACTION_URL_PREFIX.V1;
  const defaultOptions = {
    credentials: 'same-origin',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE'
  ) {
    const projectId = sessionStorage.getItem(PROJECT_ID);
    const appId = sessionStorage.getItem(APP_ID);
    const shopId = sessionStorage.getItem(SHOP_ID);
    const params = {};
    projectId && Object.assign(params, { projectId });
    appId && Object.assign(params, { appId });
    shopId && Object.assign(params, { shopId });
    newOptions.body = { ...newOptions.body, ...params };
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      };
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      };
    }
  }
  const token = window.localStorage.getItem(TOKEN);
  if (token) {
    newOptions.headers = {
      'X-Authorization': `Bearer ${token}`,
      ...newOptions.headers,
    };
  }
  const lang = localStorage.getItem(LOCALE_KEY);
  if (lang) {
    newOptions.headers = {
      'Accept-Language': lang,
      ...newOptions.headers,
    };
  }
  const requestURL = `${downLoadURL}/${url}`;
  return request(requestURL, newOptions).then(res => {
    let filename;
    if (res.headers) {
      filename = (
        res.headers.get('Content-Disposition') || res.headers.get('content-disposition')
      ).split('attachment;filename=')[1];
    }
    if (res.blob) {
      res.blob().then(blob => {
        var alink = document.createElement('a');
        alink.style.display = 'none';
        alink.target = '_blank';
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
          // 兼容IE/Edge
          window.navigator.msSaveOrOpenBlob(blob, filename);
        } else {
          alink.href = window.URL.createObjectURL(blob);
          alink.download = filename;
        }
        document.body.appendChild(alink);
        alink.click();
        URL.revokeObjectURL(alink.href); // 释放URL 对象
        document.body.removeChild(alink);
      });
      return res;
    } else {
      if (res.code === 0) {
        return res;
      } else {
        message.warning(res.message);
      }
    }
  });
};

export default exportFile;


export default function request(url: string, options: Object) {
  const defaultOptions = {
    credentials: 'same-origin',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE' ||
    newOptions.method === 'PATCH'
  ) {
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      };
      newOptions.body = JSON.stringify(newOptions.body);
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      };
    }
  }

  return fetch(url, newOptions).then(response => checkStatus(response, url, options));
}


方式二的缺点:

**如果文件小还行,文件大了就会出现点击了下载,但是没有反应,过了几分钟后才出现了下载,这种等待时间就是将服务器端的那个文件转成了blob(res.blob()花的时间特别长),才进行a标签的流式下载(这里页面才开始出现有下载的交互体现)

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值