封装 downloadFile 函数,从服务器下载文件

实现的功能

downFile.js 文件主要实现一个 downloadFile 函数,用于从服务器下载文件。该函数支持多种请求方法(如 get、postForm、post、postFile),并根据不同的请求方法构建请求配置。同时,函数会处理加载状态,根据不同浏览器处理文件下载,还能处理服务器返回的普通对象数据和文件流数据。

代码

js 复制代码
import axios from 'axios';
import qs from 'qs';
import { message } from 'antd';

export default function downloadFile(
  url,
  parmas,
  method = 'get',
  callBackData, // 回调
) {
  // 从响应头中提取文件名
  function getFilenameFromHeaders(headers) {
    const contentDisposition = headers['content-disposition'];
    if (!contentDisposition) return '';
    const [, name] = contentDisposition.split(';');
    const [, fileName] = name.split('filename=');
    return decodeURIComponent(fileName.trim());
  }
  
  // 该函数用于处理文件下载,根据浏览器类型(是否为 IE)采用不同的下载方式。该函数也可以提取为一个单独的文件,比如服务端返回的是json,某些情况才需要下载的时候,可以callBackData拿到数据去做一些判断之后再进行文件下载
  const download = (response) => {
    const filename = getFilenameFromHeaders(response.headers);
    const blob = new Blob([response.data]);
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(blob, filename);
    } else {
      const downloadElement = document.createElement('a');
      const href = window.URL.createObjectURL(blob);
      downloadElement.href = href;
      downloadElement.download = filename;
      document.body.appendChild(downloadElement);
      downloadElement.click();
      document.body.removeChild(downloadElement);
      window.URL.revokeObjectURL(href);
    }
  };

  // 使用对象映射来返回不同请求的config参数
  const methodConfigMap = {
    get: (getUrl, getParmas) => ({
      method: 'get',
      url: `${getUrl}?${qs.stringify(getParmas)}`,
      responseType: 'blob',
    }),
    postForm: (getUrl, getParmas) => ({
      method: 'post',
      url: `${getUrl}`,
      data: qs.stringify(getParmas),
      responseType: 'blob',
    }),
    post: (getUrl, getParmas) => ({
      method: 'post',
      url: `${url}`,
      data: { ...getParmas },
      responseType: 'blob',
    }),
    postFile: (getUrl, getParmas) => ({
      method: 'post',
      url: `${url}`,
      data: getParmas,
      responseType: 'blob',
    }),
  };
  const config = methodConfigMap[method]?.(url, parmas) || {};
  axios(config)
    .then((response) => {
      const reader = new FileReader();
      reader.readAsText(response.data, 'utf-8');
      reader.onload = (e) => {
        try {
          // 是普通对象数据
          const jsonData = JSON.parse(e.target.result);
          callBackData && callBackData(jsonData);
          message.error(jsonData.message || jsonData.msg);
        } catch (err) {
          // 是流文件直接下载
          callBackData && callBackData();
          download(response);
        }
      };
    })
    .catch((err) => {
      message.error(err.message); 
    });
}

应用场景

比如业务中的批量导出,上传文件之后服务端返回给前端的结果为文件流(这里可能是上传结果异常数据)。

使用实例

  1. 直接通过服务端提供的url下载
js 复制代码
import downloadFile from '@utils/downFile';

    // 批量导出
    const batchExport = useCallback(() => {
      const url = 'api/export.do';
      // 有选中的数据导出选中的数据,没有选中的数据导出全部
      const param = { id, detailIds: selectedkeys.length === 0 ? '' : selectedkeys.join(',') };
      downloadFile(url, param, 'postForm');
    }, [dispatch, id, selectedkeys]);

2.上传文件之后,服务端直接返回一个数据流或者json,不另外提供下载接口

js 复制代码
  const callBackData = useCallback(
    (data) => {
      setImporting(false);
      closeFun();
      reloadPage();
      // 这里可以对data做一些判断,
      // 或者是前端把文件暂存到变量,展示一个结果弹窗,让用户点击的时候执行download函数并把暂存的文件流作为参数传递给download函数
      if (data?.code === 900) {
        message.success('导入成功');
      }
    },
    [closeFun, reloadPage],
  );

  // 导入(上传)
  const importFile = useCallback(() => {
    setImporting(true);
    const params = new FormData();
    params.append('file', fileInfo);
    downloadFile(
      'api/batchImportToPaid.do',
      params,
      'postFile',
      callBackData,
    );
  }, [callBackData, fileInfo]);
相关推荐
怕浪猫1 小时前
Claude Code vs Codex:Computer Use 实现原理深度拆解
算法·面试·github
itmigrate1 小时前
前端项目里,Object.is 并不是 === 的平替
前端
小大宇3 小时前
Vue知识点6-computed计算属性
前端·javascript·vue.js
程序员海军3 小时前
尤雨溪 : Vue 4 已经在规划中了!
前端·javascript·vue.js
2601_949970693 小时前
HumanizeDuration 跨端三方库仓颉适配全流程
前端·javascript·flutter
风骏时光牛马5 小时前
后端服务接口开发与性能优化
前端
kyriewen5 小时前
我让 4 个 AI 互相 review 代码,最温柔的那个下手最狠
前端·程序员·ai编程
考研保研资料分享5 小时前
无论文竞赛保研中科院植物所:三场考核、科研追问与准备复盘
面试
计算机魔术师5 小时前
493家公司白砸AI钱?Apollo这组数据戳破了幻觉
前端
救救孩子把5 小时前
AI面试八股文-23_23-Agent可观测性与生产监控面试题
人工智能·面试·职场和发展·agent·langsmith·langfuase