封装 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]);
相关推荐
liangshanbo12152 小时前
JavaScript 面试题:Object.keys() 的返回顺序是无序的吗?
开发语言·javascript·ecmascript
geovindu2 小时前
css: Timeline scribble
前端·css·iphone
怕浪猫7 小时前
GEO 优化到底是什么?AI时代内容创作者必须懂的新技能
算法·面试·github
沙漠之主10 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty10 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn11 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow12 小时前
ai agent --- 文件存储
前端
Frag0ut12 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT大白鼠13 小时前
搜索系列 · 第 08 篇——面试收官:高频题与全景总结
elasticsearch·面试·nosql
IT_陈寒13 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端