You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase-Admin无法上传图片至Firebase问题求助

解决Multer + Firebase Functions本地调试时的"Unexpected end of form"错误

问题重现

使用Firebase Admin、Node.js、Express和Multer实现图片上传至Firebase Storage,本地通过firebase serve启动模拟器,用Postman测试/uploadImage接口时,持续抛出以下错误:

Error: Unexpected end of form
>      at Multipart._final (/Users/user/Desktop/FitStop-Functions/functions/node_modules/busboy/lib/types/multipart.js:588:17)
>      at prefinish (node:internal/streams/writable:906:14)
>      at finishMaybe (node:internal/streams/writable:920:5)
>      at Writable.end (node:internal/streams/writable:835:5)
>      at onend (node:internal/streams/readable:946:10)
>      at process.processTicksAndRejections (node:internal/process/task_queues:77:11)

上传核心代码如下:

const functions = require("firebase-functions");
const app = require("express")();
const { bucket } = require("./util/admin");
const multer = require("multer");

const storage = multer.memoryStorage();
const upload = multer({
    storage: storage,
    limits: { fileSize: 8 * 1024 * 1024 },
    fileFilter: (req, file, cb) => {
        if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
            return cb(new Error("Only image files are allowed!"), false);
        }
        cb(null, true);
    },
});

app.post("/uploadImage", upload.single("file"), async (req, res) => {
    console.log(req.file);
    if (!req.file) {
        return res.status(400).send("No file uploaded.");
    }

    const fileName = `uploads/${Date.now()}_${req.file.originalname}`;
    try {
        const fileUpload = bucket.file(fileName);

        const blobStream = fileUpload.createWriteStream({
            metadata: {
                contentType: req.file.mimetype,
            },
        });

        blobStream.on("error", (error) => {
            console.error("Blob stream error:", error);
            return res.status(500).json({ error: error.message });
        });

        blobStream.on("finish", async () => {
            await fileUpload.makePublic();
            const publicUrl = `https://storage.googleapis.com/${bucket.name}/${fileName}`;
            res.status(200).json({
                message: "File uploaded successfully",
                url: publicUrl,
            });
        });

        blobStream.end(req.file.buffer);
    } catch (error) {
        console.error("Upload error:", error);
        res.status(500).json({ error: "Internal server error" });
    }
});

exports.api = functions.https.onRequest(app);

核心原因

Firebase Functions本地模拟器(firebase serve)默认会自动解析所有请求体,包括multipart/form-data格式的请求。这会导致Multer依赖的Busboy无法获取完整的原始表单数据,从而触发"Unexpected end of form"错误。

解决方案

方案1:禁用Firebase Functions的自动请求体解析

修改函数导出代码,添加rawBody: true配置,让Firebase Functions保留原始请求体,交给Multer处理:

exports.api = functions.https.onRequest({ rawBody: true }, app);

方案2:调整Postman请求配置

确保Postman的请求设置正确,避免手动干扰表单解析:

  • 请求方法选择POST
  • Body类型选择form-data
  • 表单键名设置为file(与代码中upload.single("file")的参数一致)
  • 对应值选择「File」类型,上传符合要求的图片文件(jpg/jpeg/png)
  • 不要手动设置Content-Type请求头,让Postman自动生成带边界标识的multipart/form-data头

方案3:排查依赖版本冲突

如果上述方案无效,可能是Multer与Busboy的版本不兼容:

  • 尝试降级Multer到稳定版本:npm install multer@1.4.5-lts.1
  • 清除node_modules和package-lock.json,重新安装依赖:
    rm -rf node_modules package-lock.json
    npm install
    

内容的提问来源于stack exchange,提问作者lamb p

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 14:38:17