繁体   English   中英

访问 Express 中的文件上传表单数据

[英]Access file upload formData in Express

如何访问API中的文件?

我阅读了其他解决方案,它们都需要 npm 包来解决这个问题。 我想明白为什么我不能做香草。 此外,答案很旧,建议使用 body-parser,它现在与 Express 捆绑在一起。

我希望解决方案是香草 JS,以便更好地理解该过程。

客户

async function uploadFile(file) {
    let formData = new FormData();
    formData.append("file", file);

    let res = await fetchPostFile("/api/files", formData);
}

拿来

export async function fetchPostFile(url, formData) {
    try {
        let result = await (
            await fetch(url, {
                method: "POST",
                withCredentials: true,
                credentials: "include",
                headers: {
                    Authorization: localStorage.getItem("token"),
                    Accept: "application/json",
                    "Content-type": "multipart/form-data",
                },
                body: formData,
            })
        ).json();

        return result;
    } catch (err) {
        return err;
    }
}

api

router.post("/api/files", async function (req, res, next) {
    try {
        console.log(req.file);          // undefined
        console.log(req.files);         // undefined
        console.log(req.body);          // {}

    } catch (err) {
        next(err);
    } finally {
        req.connection.release();
    }
});

为什么req.body是空的? 请帮助我了解我做错了什么。

首先,您需要使用multer package 来处理 express 中的multipart/form-data 您必须将其用作中间件来设置文件的字段名称。 作为参数传递给single() function 的名称必须与客户端附加的名称匹配。

const multer = require('multer')

router.post("/api/files", multer().single('file'), async function (req, res, next) {
  try {
      console.log(req.file)
  } catch (err) {
      next(err)
  } finally {
      req.connection.release()
  }
});

这是整个文件管理 API。

我正在使用busboy ,这是multer在后台使用的。 我发现它更容易使用。

const express = require("express");
const router = express.Router();

const config = require("../../config");

const busboy = require("busboy");
const fs = require("fs");

const SHA256 = require("crypto-js/sha256");

let filesFolderPath = config.paths.files;

router.get("/api/records/:recordUid/files/:fieldUid", async (req, res, next) => {
    try {
        let { recordUid, fieldUid } = req.params;

        let query = `
            select 
                rdf.*,
                r.uid recordUid,
                round(sizeBytes / 1024, 0) sizeKb,
                round(sizeBytes / 1024 / 1024, 0) sizeMb
            from recordDataFile rdf
                left join record r on r.id = rdf.recordId
                left join field f on f.id = rdf.fieldId
            where 
                r.uid = ?
                and f.uid = ?;
        `;

        let rows = await req.pool.query(query, [recordUid, fieldUid]);

        res.status(200).send(rows);
    } catch (err) {
        next(err);
    }
});

router.get("/api/files/:hash", async (req, res, next) => {
    try {
        let { hash } = req.params;

        let query = `
            select *
            from recordDataFile
            where hash = ?
        `;

        let rows = await req.pool.query(query, [hash]);
        let fileData = rows[0];

        res.download(fileData.path);
    } catch (err) {
        next(err);
    }
});

router.post("/api/files", async (req, res, next) => {
    try {
        let bb = busboy({
            headers: req.headers,
            defCharset: "utf8",
            limits: {
                fileSize: 20 * 1024 * 1024, // 20 mb
                files: 5,
            },
        });

        let fields = {};

        // Get any text values
        bb.on("field", (fieldname, val, fieldnameTruncated, valTruncated) => {
            console.log(fieldname, val);
            fields[fieldname] = val;
        });

        // Read file stream
        bb.on("file", (fieldname, fileStream, filename, encoding, mimetype) => {
            // Prevents hieroglyphs from cyrillic
            let originalName = Buffer.from(filename.filename, "latin1").toString("utf8");

            let nameParts = originalName.split(".");
            let extension = nameParts[nameParts.length - 1]; // without the . from .jpeg

            // IMPORTANT!!! FILE NAME CAN'T HAVE SPACES, it won't save properly!!!
            let hash = SHA256(`${+new Date()}${originalName}`).toString();

            // Absolute path to file
            let filePath = `${filesFolderPath}${hash}`;

            // Open writeable stream to path
            let writeStream = fs.createWriteStream(filePath);

            // Pipe the file to the opened stream
            fileStream.pipe(writeStream);

            // Check for errors
            writeStream.on("error", (err) => {
                console.log("writeStream", err);
            });

            // Writing done, stream closed
            writeStream.on("close", async (err) => {
                // console.log("closing + SQL");

                if (err) {
                    console.log("closing error");
                    return;
                }

                let query = `
                    insert into recordDataFile
                        (
                            recordId,
                            fieldId,
                            name,
                            extension,
                            hash,
                            path,
                            sizeBytes,
                            userId,
                            created
                        )
                    values
                        (
                            (select id from record where uid = ?),
                            (select id from field where uid = ?),
                            ?,
                            ?,
                            ?,
                            ?,
                            ?,
                            ?,
                            now()
                        );
                `;

                let sizeBytes = fs.statSync(filePath).size;

                await req.pool.query(query, [fields.recordUid, fields.fieldUid, originalName, extension, hash, filePath, sizeBytes, req.userId]);

                // record updated. send notification?
                await req.pool.query(`update record set updated = now(), updatedByUserId = ? where uid = ?`, [req.userId, fields.recordUid]);
            });
        });

        bb.on("finish", () => {
            res.status(200).send({ success: true });
        });

        req.pipe(bb); // Hooks the streams together. Without it, you're not feeding busboy any data to parse.
    } catch (err) {
        console.log("file upload catch", err);
        next(err);
    }
});

router.delete("/api/files/:hash", async (req, res, next) => {
    try {
        let { hash } = req.params;

        // get the file
        let query = `
            select * from recordDataFile where hash = ?
        `;

        let rows = await req.pool.query(query, [hash]);

        let file = rows[0];
        let filePath = file.path;

        // remove file
        fs.unlinkSync(filePath);

        // delete the file metadata
        await req.pool.query(` delete from recordDataFile where hash = ?`, [hash]);

        res.status(200).send(rows);
    } catch (err) {
        next(err);
    }
});

module.exports = router;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM