无法使用 firebase 功能将图像上传到 firebase 存储
Posted
技术标签:
【中文标题】无法使用 firebase 功能将图像上传到 firebase 存储【英文标题】:Unable to upload image to firebase storage with firebase functions 【发布时间】:2020-03-05 04:58:29 【问题描述】:这是我的代码:-
exports.uploadImage = (req, res) =>
const BusBoy = require('busboy');
const path = require('path');
const os = require('os');
const fs = require('fs');
const busboy = new BusBoy( headers: req.headers );
let imageFileName;
let imageToBeUploaded = ;
busboy.on('file', (fieldname, file, filename, encoding, mimetype) =>
const imageExtension = filename.split('.')[filename.split('.').length - 1];
imageFileName = `$Math.round(Math.random() * 100000000000).$imageExtension`;
const filepath = path.join(os.tmpdir(), imageFileName);
imageToBeUploaded = filepath, mimetype ;
file.pipe(fs.createWriteStream(filepath));
);
busboy.on('finish', () =>
console.log('Busboy on started');
//code breaks here
admin.storage().bucket().upload(imageToBeUploaded.filepath,
resumable: false,
metadata:
metadata:
contentType: imageToBeUploaded.mimetype
)
.then(() =>
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/$config.storageBucket/o/$imageFileName?alt=media`;
console.log('logging image url' + imageUrl);
return db.doc(`/users/$req.user.handle`).update( imageUrl )
)
.then(() =>
return res.json( message: 'Image uploaded successfully' );
)
.catch(err =>
console.error(err);
return res.status(500).json( error: err.code );
)
);
busboy.end(req.rawBody);
我在评论中提到了我的代码在哪里中断,我得到的错误是Error: Cannot parse response as JSON: Not Found
message: 'Cannot parse response as JSON: Not Found'
错误消息显示无法将响应解析为JSON
。这是否意味着来自 firebase 的响应不是 JSON?我在请求的标头中有一个令牌,在正文中有一个图像作为表单数据。我真的不知道哪里出了问题,请帮忙
【问题讨论】:
你有没有试过把它变成一个minimal, complete, reproducible example(例如,一个只查看存储调用的单独的?特别是因为你混合了firebase风格(例如使用管理API)和非 firebase 风格(您的云函数声明),有一些完整的东西可以重现会很有帮助。 另一个观察结果——与其将输入文件通过管道传输到文件系统,然后通过upload()
将其读回,不如使用 GCS createWriteStream API 并直接通过管道传输。跨度>
@robsiemb 实际上我正在关注一个在线教程,代码来自该教程,所以我不知道我遵循什么风格
@robsiemb 你能说出你的意思是什么吗?
管道:调用file.pipe()
写入流。当您可以直接写入通过createWriteStream
api 进入 GCS 的流时,没有理由写入文件系统然后从文件系统读回。
【参考方案1】:
在我的情况下,存储桶 ID 配置错误 - 更正后我能够上传文件
【讨论】:
【参考方案2】:很遗憾,我无法识别 JSON 解析错误,因此我改写了代码,使其更加精简,因为 @robsiemb 没有解决。
您的uploadImage
函数似乎被配置为一些中间件,所以我在下面做了同样的事情。此代码将使用从Reference.push().key
生成的唯一文件名将上传的数据直接流式传输到 Cloud Storage,以防止冲突。
在下面的代码中,
上传的文件将存储在类似的位置:userData/someUserId/images/-JhLeOlGIEjaIOFHR0xd.png
图像的原始 URL 不会存储在数据库中,因为除非文件对象或包含的存储桶被公开,否则它将需要一个 signed URL,它最多只能持续 7 天(见下文)。
可以接受和上传多个文件。如果不希望这样做,请配置 limits for the BusBoy
instance。
添加了对非 POST 请求和丢失文件条目的基本错误处理。
// import Firebase libraries & initialize
const admin = require('firebase-admin');
admin.initializeApp(); // initializes from environment variables
// import required modules
const BusBoy = require('busboy');
exports.uploadImage = (req, res) =>
if (req.method !== 'POST')
res.sendStatus(405); // 405 METHOD_NOT_ALLOWED
return;
let busboy = new BusBoy(headers: req.headers); // add limits: files: 1 to limit to only a single file upload
let bucket = admin.storage().bucket();
let db = admin.firestore();
let storageFilepath;
let storageFile;
// Note: Currently only the last file is saved to `/users/$req.user.handle`
busboy.on('file', (fieldname, file, filename, encoding, mimetype) =>
let fileext = filename.match(/\.[0-9a-z]+$/i)[0];
storageFilepath = `userData/$req.user.handle/images/` + getUniqueName() + fileext;
storageFile = bucket.file(storageFilepath);
file.pipe(storageFile.createWriteStream( gzip: true ));
)
.on('finish', () =>
if (!storageFile)
res.status(400).json(error: 'expected file'); // 400 BAD_REQUEST
return;
db.doc(`/users/$req.user.handle`).update( imagePath: storageFilepath )
.then(() =>
res.status(201).json( message: 'Image uploaded successfully' ); // 201 CREATED
)
.catch((err) =>
console.error(err);
res.status(500).json( error: err.code ); // 500 INTERNAL_SERVER_ERROR
);
)
.on('error', (err) =>
console.error(err);
res.status(500).json( error: err.code );
);
req.pipe(busboy);
);
function getUniqueName()
// push() without arguments returns a ThennableReference, which we'll abuse for it's key generation
return admin.database().ref().push().key;
如果您确实希望上传的图片可以公开访问,您可以使用添加到 File.makePublic()
函数中的以下 .on('finish', ...)
处理程序:
.on('finish', () =>
if (!storageFile)
res.status(400).json(error: 'expected file'); // 400 BAD_REQUEST
return;
storageFile.makePublic()
.then(() =>
return db.doc(`/users/$req.user.handle`).update(
imagePath: storageFilepath,
imageUrl: `https://storage.googleapis.com/$config.storageBucket/$storageFilepath`
);
)
.then(() =>
res.status(201).json( message: 'Image uploaded successfully' ); // 201 CREATED
)
.catch((err) =>
console.error(err);
res.status(500).json( error: err.code ); // 500 INTERNAL_SERVER_ERROR
);
)
【讨论】:
【参考方案3】:找到解决问题的办法!
基本上 - 您需要设置您的 Google 应用程序凭据。进入firebase并查看您的设置。您需要设置环境变量 GOOGLE_APPLICATION_CREDENTIALS 以便 firebase 在您访问这些文件时拥有您的凭据。
https://firebase.google.com/docs/admin/setup?authuser=1 了解更多信息。
完成后,检查 Firebase 中的安全设置,在您处理的每个区域。这应该可以解决问题(这绝对是安全问题,而不是您的代码)。
对于那些正在寻找的人来说,这也是有问题的教程。 https://www.youtube.com/watch?v=m_u6P5k0vP0&t=7661s.
【讨论】:
以上是关于无法使用 firebase 功能将图像上传到 firebase 存储的主要内容,如果未能解决你的问题,请参考以下文章
当我将图像上传到 Firebase 时,来自 Database Realtime 的图像 url 与 firebase 存储中的图像 url 不同