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

实现的功能

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

代码

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 小时前
【前端独角兽】刚进入前端领域的前端开发用jQuery还是Vue3?
前端·javascript·vue3·jquery
IMPYLH2 小时前
HTML 的 <data> 元素
前端·html
YHHLAI2 小时前
[特殊字符] 面试中的 Promise —— 从入门到精通
前端·javascript·面试
weixin_BYSJ19873 小时前
SpringBoot + MySQL 乒乓球运动员信息管理系统项目实战--附源码04954
java·javascript·spring boot·python·django·flask·php
沪飘大军3 小时前
ll-llm:一个零依赖、可插拔的 OpenAI 兼容 LLM 代理
javascript
kyriewen4 小时前
我扒了 GPT-5.6 的全部编程跑分——有一项 OpenAI 没敢放出来
前端·gpt·ai编程
前端H5 小时前
微前端 v3 架构升级:从加载隔离到状态协同
前端·架构·状态模式
山河木马5 小时前
GPU自动处理专题3-NDC怎么映射成屏幕像素坐标(视口变换)
javascript·webgl·图形学
陆枫Larry6 小时前
小程序包体积优化:用 SVG 图片替换 iconfont,并保留 CSS 控色能力
前端
Appthing6 小时前
在 TanStack Start 中使用 VitePWA 的正确配置
javascript