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

在Firebase Cloud Functions中用Express+Busboy实现POST请求及排障

解决方案:使用Busboy在Firebase Functions中处理form-data上传并插入数据库

你原代码存在几个关键问题:

  • 注释掉了const imagerUrl = await uploadImageToStorage(reqFiles),导致reqFilesUrl未定义,无法正确存储图片URL到数据库
  • 混用await和回调函数处理notify.save(),异步逻辑执行顺序混乱
  • 在Firebase Functions环境下,直接用multer可能存在适配问题,Busboy是更适合处理multipart/form-data的轻量方案

以下是基于Busboy的完整修正代码,替换你原有的router.post部分及相关配置:

const express = require('express')
const router = new express.Router()
const userInfo = require('../models/userProfile')
var fs = require('fs');
var path = require('path');
const {Storage} = require('@google-cloud/storage');
const {format} = require('util');
const busboy = require('busboy');

const storage = new Storage({
  projectId: "biz-1",
  keyFilename: "/Users/akm/pixNodes/functions/pixbiz-65a402.json"
});

const bucket = storage.bucket("gs://biz-1");

const uploadImageToStorage = (file) => {
  return new Promise((resolve, reject) => {
    if (!file) {
      reject('No image file');
    }
    let newFileName = `${Date.now() + path.extname(file.originalname)}`;

    let fileUpload = bucket.file(newFileName);

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

    blobStream.on('error', (error) => {
      reject('Something is wrong! Unable to upload at the moment.');
    });

    blobStream.on('finish', () => {
      const url = format(`https://storage.googleapis.com/${bucket.name}/${fileUpload.name}`);
      resolve(url);
    });

    blobStream.end(file.buffer);
  });
}

router.post('/userprofile/check', async (req, res) => {
  try {
    const bb = busboy({ headers: req.headers });
    let formData = {};
    let uploadedFile = null;

    // 处理表单字段
    bb.on('field', (name, val) => {
      formData[name] = val;
    });

    // 处理文件上传
    bb.on('file', (name, file, info) => {
      const { filename, mimeType } = info;
      const chunks = [];
      file.on('data', (chunk) => chunks.push(chunk));
      file.on('end', () => {
        uploadedFile = {
          originalname: filename,
          mimetype: mimeType,
          buffer: Buffer.concat(chunks)
        };
      });
    });

    // 所有数据解析完成后执行逻辑
    bb.on('finish', async () => {
      let profilePicUrl = null;
      if (uploadedFile) {
        profilePicUrl = await uploadImageToStorage(uploadedFile);
      }

      // 创建用户数据
      const userProfile = new userInfo({
        userId: formData.userId,
        mobile_number: formData.mobileNumber,
        profile_pic: profilePicUrl
      });

      // 保存到数据库(使用async/await而非回调)
      const savedProfile = await userProfile.save();
      console.log('数据插入成功');
      res.status(201).send(savedProfile);
    });

    // 开始解析请求
    req.pipe(bb);
  } catch (e) {
    console.error('处理请求出错:', e);
    res.status(500).send({ error: e.message });
  }
});

关键说明:

  1. Busboy核心逻辑:

    • 通过busboy({ headers: req.headers })初始化解析器,绑定请求头
    • 监听field事件获取表单文本字段(如userId、mobileNumber)
    • 监听file事件读取上传文件的二进制数据,拼接成Buffer后传入GCS上传函数
    • 监听finish事件,在所有数据解析完成后执行数据库插入操作
  2. 修复原代码问题:

    • 移除了multer依赖,改用Busboy直接处理请求,适配Firebase Functions环境
    • 正确使用async/await处理异步操作(GCS上传、数据库保存),避免回调混用导致的逻辑错误
    • 确保图片URL正确获取后再插入数据库
  3. 注意事项:

    • 确保你的userInfo模型中userId、mobile_number、profile_pic字段定义正确
    • 测试时确保POST请求的form-data中字段名与代码一致(userId、mobileNumber、profile_pic)
    • Firebase Functions的内存配置建议至少设置为256MB,避免大文件上传时内存不足

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:31:22