我有一个 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 函数,但得到与模拟器相同的行为。
我找不到任何对 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));
我一直在处理同样的错误,我想我已经解决了。当满足以下两个条件时:
multipart/form-data
(用于文件和图像上传的类型,如您提到的端点)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 标头。