Ant Design Upload 组件+Busboy 的 Node.js 文件上传实现

51 阅读1分钟

Busboy是一个非常的Node.js库,用于处理multipart/form-data格式的文件上传,常用于Express.js等框架中的文件上传功能。它通过流(Stream)处理上传的文件,因此能够处理大文件。

前端使用的是Ant Design中的 Upload 组件 后端使用的是Node.js以及第三方库Busboy 代码实现如下:


    <Upload 
    key="dbbackup"
    name="dbbackup"
    accept={[".tgz",".txt"]}
    action="api/file/upload?type=dbbackup"
    multiple
    onChange={rs => {
        setUploading(["uploading"].includes(rs?.file?.status));
        if (rs?.file?.status === "error") {
            message.error(gLabelList.upload_failed);
            return;
        }
        if (rs?.file?.status === "done") {
            message.error(gLabelList.upload_sucess);
        }
    }}
    >
    <Button type="primary">上传</Button>
    </Upload>

后端代码实现:

    const fs = require("fs");
    const busboy = require("busboy");
    const express = require("express");
    const router = express.Router();
    const uploadPath = path.join(process.cwd(), "upload");
    const dbbackupPath = path.join(process.cwd(), "dbbackup");

    router.post("/upload", (req, res) => {
        try {
            // 从请求的查询字符串(req.query)中提取type参数,type用于决定文件的处理方式或保存位置。
            const {type} = req.query;
            const bb = busboy({headers: req.headers});
            let fileName;
            
            // 注册file事件监听器,用于处理上传的文件。当有文件上传时,name是字段名(文件上传时的字段字段名称),file是文件流,info包含文件的相关信息(如文件名、文件类型等)
            bb.on("file", (name, file, info) => {
            
           // 将上传的文件名(info.filename)从二进制转换为UTF-8编码的字符串,以确保文件名正确处理(特别是在不同编码的情况下)。
            fileName = info.filename = Buffer.from(info.filename, "binary").toString("utf8");
            
           // 根据type的值来决定文件保存的路径:
          // 如果type为"dbbackup",文件将被保存到dbbackupPath目录中。
          // 如果type为其他值,文件将被保存到uploadPath/type目录下。
          // file.pipe()将文件流写入到指定路径的文件中。
                type === "dbbackup"
                    ? file.pipe(fs.createWriteStream(path.join(dbbackupPath, fileName)))
                    : file.pipe(fs.createWriteStream(path.join(uploadPath, type, fileName)));
            }).on("close", async () => {
                // 注册close事件监听器,该事件在文件处理完成后触发,表示文件上传已完成。
                const fileList = type === "dbbackup"
                        ? fs.readdirSync(path.join(dbbackupPath)).map(name => ({uid: name, name}))
                        : fs.readdirSync(path.join(uploadPath, type)).map(name => ({uid: name, name}));
                res.json({apiResult: "complete", fileList});
            });
            return req.pipe(bb);
        } catch (e) {
            res.json({apiResult: "fail", apiMessage: e});
        }
    });
    module.exports = router