For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /blog/upload/blob-export.md.

二进制流文件导出

场景需求

开发后台管理系统时,难免会涉及到文件的上传和文件的导出。现在前端上传文件主要采用“二进制文件流”的形式来上传文件。上传主要方式有以下方式:

  • 前端直接传递云存储或者自身服务器,来获取上传文件的云端绝对地址;
  • 前端借助后台来实现文件的存储和上传,然后经后台处理来返回文件存储路径。

上传文件也根据文件格式进行分类存储或者在上传前进行文件的大小和格式的校验处理,以防乱传递垃圾文件消耗云盘存储空间和浪费流量等。

文件格式

后台管理系统一般用作处理文档数据相关,导出的数据大致分为以下几类:

  • 用于数据统计的Excel文件,主流文件格式为:.xls 和 .xlsx;
  • 用于文档通知的Word文件,主流文件格式为:.doc和 .docx;
  • 用于幻灯片的PowerPoint文件,主流文件格式为:.ppt 和 .pptx;

文件导出

  1. 从后台 API 获取二进制流文件地址,进行处理;

  2. 配置前端请求方式,以 blob 的方式请求获取文件流;

  3. 通过 URL.createObjectURL() 静态方法创建一个DOMString;

  4. 动态创建用于文件下载的 a 标签,并赋值 herf 和 download 属性,并触发该标签的点击事件;

  5. 通过 URL.revokeObjectURL() 静态方法来释放之前通过 URL.createObjectURL() 创建的 URL 对象。

代码示例

代码示例
/* 时间戳 */
const timeStamp = () => {
    const date = new Date();

    let yyyy = date.getFullYear(),
        MM = date.getMonth() + 1,
        dd = date.getDate(),
        hh = date.getHours(),
        mm = date.getMinutes(),
        ss = date.getSeconds();
    // 补0
    MM = MM < 10 ? "0" + MM : MM;
    dd = dd < 10 ? "0" + dd : dd;
    hh = hh < 10 ? "0" + hh : hh;
    mm = mm < 10 ? "0" + mm : mm;
    ss = ss < 10 ? "0" + ss : ss;

    let timeStr = `${yyyy}${MM}${dd}${hh}${mm}${ss}`;
    return timeStr;
};

/* 导出数据 */
const exportData = () => {
    // 所需参数
    let params = {};

    axios
        .get("API", { responseType: "blob", params })
        .then((res) => {
            setTimeout(() => {
                // 获取文件流,生成 URL 对象
                let url = window.URL.createObjectURL(res.data);
                // 创建用于下载的 a 标签
                let link = document.createElement("a");
                // 隐藏动态创建的 a 标签
                link.style.display = "none";
                // 设置 herf 属性并赋值生成的 url 文件地址
                link.href = url;
                // 生成时间戳
                let timeStr = timeStamp();
                /**
                 * 重命名文件名
                 * 格式必须以 “.文件格式后缀名”的形式结尾
                 *  */
                let fileName = `${timeStr}.xls`;
                // 设置被下载的超链接目标
                link.setAttribute("download", fileName);
                // 触发 a 标签跳转
                link.click();
                // 释放 URL 对象
                window.URL.revokeObjectURL(url);
            }, 500);
        })
        .catch((err) => {
            console.log("导出失败:", err);
        });
};

🚐 注:文件后缀名根据要求进行定义。

代码示例
// 文件命名格式

// 5位数随机数
let timeStr = parseInt(Math.random(0, 1) * 1e5);

// 当前时间戳
let timeStr = new Date().toLocaleString();

// 获取headers中的文件名
let fileName = res.headers["content-disposition"]
    .split(";")[1]
    .split("filename=")[1];

🐻 注:上述“获取 headers 中的文件名”为在请求接口时后台携带的文件名,若“无”则需自定义文件名。


Axios blob 请求导出示例

基于 axios responseType: blob 的极简导出写法。

使用场景

文件的导入导出。

节流函数 Debounce

代码示例
/**
 * 返回值文件类型为 blob 二进制流文件
 * responseType: 'blob'
 * params 接口所需参数
 * 命名文件名:依据时间戳命名文件名
 * 			(导出时需要延迟,否则导出文件失败,默认文件名时直接导出)
 * */
$axios
    .get(`api`, {
        responseType: "blob",
        params,
    })
    .then((res) => {
        // response 的返回值为二进制文件流

        // 创建时间戳
        let date = new Date(),
            yyyy = date.getFullYear(),
            MM = date.getMonth() + 1,
            dd = date.getDate(),
            hh = date.getHours(),
            mm = date.getMinutes(),
            ss = date.getSeconds();
        var timeStr = `${yyyy}${MM}${dd}${hh}${mm}${ss}`;

        // 导出二进制文件
        setTimeout(() => {
            // 创建URL对象 URL.createObjectURL(object)
            let url = window.URL.createObjectURL(res.data);
            let link = document.createElement("a");
            link.style.display = "none";
            link.href = url;
            // 指定文件名&文件类型(后缀名)
            let fileName = `Users${timeStr}CN.xls`;
            /**
             * 添加属性,并赋指定的值 el.setAttribute('download','zzz')
             * demo: <a href="abc.gif" download="zzz">
             * download属性的值即使当前要导出的文件的文件名
             * */
            link.setAttribute("download", fileName);
            link.click();
            // 释放创建的对象(创建的新的URL必须通过该方法释放)
            window.URL.revokeObjectURL(url);
        }, 500);
    })
    .catch((err) => {
        console.log("文件导出失败: ", err);
    });