fetch下载文件--统一拦截导出文件

做外卖报表导出功能,前端使用fetch请求,后端在正常情况向会返回csv文件,在异常时会返回对应的异常码;前端的请求都是使用request.js做了统一拦截和错误提示,但是不支持文件下载,于是对原有内容稍作改造,支持文件下载。

前端是怎么实现文件下载的?

// 使用fetch发送请求并拿到返回值
 const response = await fetch(newUrl, responseBody);
// 将文件流转为blob对象,并获取本地文件链接
 response.blob().then((blob) => {
      const a = window.document.createElement('a');
      const downUrl = window.URL.createObjectURL(blob);// 获取 blob 本地文件连接 (blob 为纯二进制对象,不能够直接保存到磁盘上)
      const filename = response.headers.get('Content-Disposition').split('filename=')[1].split('.');
      a.href = downUrl;
      a.download = `${decodeURI(filename[0])}.${filename[1]}`;
      a.click();
      window.URL.revokeObjectURL(downUrl);
    });

实际场景中需要区分返回的是否是文件,文件走下载方法,数据走原有的request.js中定义的方法,这里需要使用响应头的Content-Type来判断,这里后端直返回CSV文件所以使用response.headers.get('Content-Type').indexOf('application/msexcel') > -1来判断是否为文件下载(响应头与后端约定好了)。

if (response.headers.get('Content-Type').indexOf('application/msexcel') > -1) {
    response.blob().then(
      执行文件下载
    )
} else {
     response.json();
     原有数据处理方法
}

request.js

import fetch from 'dva/fetch';
import { stringify } from 'qs';
import { message } from 'antd';
import { getFormData } from './index';

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 *
/* message.config({
  top: 10,
  duration: 5,
  getContainer: () => window.document.getElementById('root'),
});*/
export default async function request(url, options) {
  let newOptions;
  let newUrl = url;
  let responseBody = {};
  let data = {};
  const { body, params } = options;
  // 判断请求类型
  if ((!(typeof body === 'string')) && body) {
    newOptions = Object.assign({}, options, { body: getFormData(body) });
    responseBody = {
      credentials: 'same-origin',
      ...newOptions,
    };
  } else {
    newOptions = options;
    responseBody = {
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/json',
      },
      ...newOptions,
    };
  }
  // get
  if (params) {
    newUrl += `?${stringify(params)}`;
  }
  const response = await fetch(newUrl, responseBody);
  // 报表导出 Content-Type为application/msexcel时,为文件流,进行下载操作
  if (response.headers.get('Content-Type').indexOf('application/msexcel') > -1) {
    response.blob().then((blob) => {
      const a = window.document.createElement('a');
      const downUrl = window.URL.createObjectURL(blob);// 获取 blob 本地文件连接 (blob 为纯二进制对象,不能够直接保存到磁盘上)
      const filename = response.headers.get('Content-Disposition').split('filename=')[1].split('.');
      a.href = downUrl;
      a.download = `${decodeURI(filename[0])}.${filename[1]}`;
      a.click();
      window.URL.revokeObjectURL(downUrl);
    });
    return data;
  }
  if (response.status !== 200) {
    message.error('网络或服务器异常!');
    return {
      data: {
        code: response.status,
      },
    };
  }
  data = await response.json();
  if (data.code !== '200') {
    // 状态码不为304或302的时候报错
    if (data.code !== '304' && data.code !== '302') {
      console.log(data.msg);
      message.error(data.msg);
    }
    // 状态码为304的时候,请求登录接口
    if (data.code === '304') {
      request('/login', {
        method: 'post',
        body: {
          ...data.data,
          redirect_uri: encodeURIComponent(window.location.href),
        },
      });
    }
    // 状态码为302的时候,进行跳转
    if (data.code === '302') {
      window.location = data.msg;
    }
  }
  return { data };
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值