使用 Firebase 函数时无法提交表单

问题描述 投票:0回答:2

我有一个 Express.js 应用程序,我使用 REST API 与 Firebase 存储和实时数据库进行交互。我设置了一个 Firebase 项目,在其中使用 Firebase Functions。我有一个主要功能,它基本上是我的 Express 应用程序的所有请求的入口点:

// export express app to functions
exports.api = functions.https.onRequest(app);

其中

app
是我的 Express 应用程序已初始化。

其中一条路由用于将图像上传到 Firebase 存储。这是它的代码:

/* POST upload user profile picture. */
router.post('/:username/upload_profile_picture', async function(req, res, next) {
  try {

    const bb = Busboy({ headers: req.headers });
    let fileData = null;
    let fileBlob = null;
    bb.on('file', function (fieldname, file, filename, encoding, mimetype) {
      const filepath = path.join(os.tmpdir(), filename.filename);
      fileData = { filePath: filepath, type: mimetype };
      file.pipe(fs.createWriteStream(filepath));
    });
    bb.on('finish', async () => {
      const profilePicture = await UserRepository.uploadProfilePicture(fileData.filePath, req.params.username);
      if (profilePicture == null) {
        res.status(400).json({ message: "Image upload failed" });
      } else {
        res.status(200).json({ message: "Image uploaded successfully", profilePicture: profilePicture });
      }
      fs.unlinkSync(fileData.filePath);
    });
    req.pipe(bb);
  } catch (error) {
    next(error);
  }
});

这是在我的 UserRepository 中调用的相应函数:

exports.uploadProfilePicture= async (filePath, user) => {
    const file = fs.readFileSync(filePath);
    const imageRef = storage_ref(storage, 'profilePictures/' + user);
    try {
        await uploadBytes(imageRef, file.buffer);
        console.log('Uploaded file to firebase');
        const url = await getDownloadURL(imageRef);
        return url;
    } catch (error) {
        console.log(error);
    }
}

当我使用

npm run dev
在本地运行 Express 应用程序时,图像上传成功。但是,每当我使用 Firebase 模拟器时,我都会收到以下错误:

>  Error: Unexpected end of form
>      at Multipart._final (/Users/cesar/ProgrammingProjects/Democrastyle/backend/node_modules/busboy/lib/types/multipart.js:588:17)
>      at callFinal (node:internal/streams/writable:698:12)
>      at prefinish (node:internal/streams/writable:710:7)
>      at finishMaybe (node:internal/streams/writable:720:5)
>      at Writable.end (node:internal/streams/writable:634:5)
>      at onend (node:internal/streams/readable:705:10)
>      at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
>  Emitted 'error' event on Multipart instance at:
>      at Multipart.onerror (node:internal/streams/readable:785:14)
>      at Multipart.emit (node:events:513:28)
>      at emitErrorNT (node:internal/streams/destroy:151:8)
>      at emitErrorCloseNT (node:internal/streams/destroy:116:3)
>      at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

我在某处读到,Multer 库导致了此问题,因为 Firebase 不支持它,这就是我迁移到使用 Busboy 的原因,但我仍然遇到相同的错误。使用 Firebase 模拟器,所有其他路线都可以正常工作。只有包含表单数据的路由失败(尽管一切都在本地运行)。

注意:我尝试部署 Firebase 函数,但得到与模拟器相同的行为。

node.js firebase google-cloud-functions firebase-storage busboy
2个回答
1
投票

我找不到任何对 storage_ref 的引用。文档和代码似乎使用

ref
https://firebase.google.com/docs/storage/web/upload-files#upload_from_a_blob_or_file

此外,您不应该需要

.buffer
中的
file
,如 uploadBytes 方法所述:

//“文件”来自 Blob 或文件 API。

尝试:

uploadBytes(storageRef, readFileSync(file.path));


0
投票

我一直在处理同样的错误,我想我已经解决了。当满足以下两个条件时:

  1. POST 请求的类型为
    multipart/form-data
    (用于文件和图像上传的类型,如您提到的端点)
  2. 该函数是通过 Firebase Hosting 重写调用的。

POST 数据未正确传输。您的函数不是

Buffer
包含表单数据,而是 接收包含 JSON 字符串的缓冲区

例如,当我调用

req.rawBody.toString()
时,我看到以下输出:

{\"type\":\"Buffer\",\"data\":[45,45,45,45,45,45,87,101,98,75,105,116,70,111,114,109,66,111,117,110,100,97,114,121,57,102,104,90,66,71,107,65,72,100,87,49,87,78,79,71,13,10,67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105,111,110,58,32,102,111...
(为了简洁省略其余部分)

如果您随后将其解析为 JSON 并对该字节数组调用

Buffer.from()
,您将看到:

------WebKitFormBoundary9fhZBGkAHdW1WNOG\r\nContent-Disposition: fo...
(为了简洁省略其余部分)

这是我们的表单数据!

因此,当 Firebase Hosting 在您的用户和函数之间设置时,Google 的某些中间件必须将我们想要的

Buffer
转换为 JSON 字符串,然后将该字符串转换为
Buffer
...似乎是一个错误,尽管我还不知道在哪里报告它。

简单的解决方法是直接调用函数的 URL,而不是 Firebase 托管 URL,但这可能需要在响应中设置一些 CORS 标头。

© www.soinside.com 2019 - 2024. All rights reserved.