从 firebase 云函数上传图像到云存储
Upload image to cloud storage from firebase cloud functions
我正在努力从云功能上传一张图片
我正在使用 onRequest 将图像从网络发送到云功能。我发送一个 base64 字符串和文件名。现在我正在按照互联网上的不同教程进行操作,但似乎无法解决我的问题。
这是我的代码。我想我在服务帐户 json 上做错了什么。虽然我生成了 json 文件并使用了它,但它仍然不起作用。
当我不使用服务帐户 json 时出现 The caller does not have permission at Gaxios._request
错误
当我使用 serviceAccount.json 然后我得到这个错误 The "path" argument must be of type string. Received an instance of Object
这是来自 file.createWriteStream()
我认为
无论如何,这是代码,任何人都可以帮我解决这个问题
我使用的projectId如下图
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const projectId = functions.config().apikeys.projectid; // In the picture below
const stream = require("stream");
const cors = require("cors")({ origin: true });
const { Storage } = require("@google-cloud/storage");
// Enable Storage
const storage = new Storage({
projectId: projectId, // I did use serviceAccount json here but that wasn't working
});
// With serviceAccount.json code
// const storage = new Storage({
// projectId: projectId,
// keyFilename: serviceAccount,
// });
// This is giving the error of: The "path" argument must be of type string. Received an instance of Object
exports.storeUserProfileImage = functions.https.onRequest((req, res) => {
cors(req, res, async () => {
try {
const bucket = storage.bucket(`gs://${projectId}.appspot.com`);
let pictureURL;
const image = req.body.image;
const userId = req.body.userId;
const fileName = req.body.fileName;
const mimeType = image.match(
/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/
)[1];
//trim off the part of the payload that is not part of the base64 string
const base64EncodedImageString = image.replace(
/^data:image\/\w+;base64,/,
""
);
const imageBuffer = Buffer.from(base64EncodedImageString, "base64");
const bufferStream = new stream.PassThrough();
bufferStream.end(imageBuffer);
// Define file and fileName
const file = bucket.file("images/" + fileName);
bufferStream
.pipe(
file.createWriteStream({
metadata: {
contentType: mimeType,
},
public: true,
validation: "md5",
})
)
.on("error", function (err) {
console.log("error from image upload", err.message);
})
.on("finish", function () {
// The file upload is complete.
console.log("Image uploaded");
file
.getSignedUrl({
action: "read",
expires: "03-09-2491",
})
.then((signedUrls) => {
// signedUrls[0] contains the file's public URL
console.log("Signed urls", signedUrls[0]);
pictureURL = signedUrls[0];
});
});
console.log("image url", pictureURL);
res.status(200).send(pictureURL);
} catch (e) {
console.log(e);
return { success: false, error: e };
}
});
});
const storage = new Storage({
projectId: projectId
keyFilename: "" // <-- Path to a .json, .pem, or .p12 key file
});
keyFilename
接受存储您的服务帐户的路径和凭据本身。
folder
|-index.js
|-credentials
|-serviceAccountKey.json
如果你的目录结构看起来像那么路径应该是这样的:
const storage = new Storage({
projectId: projectId
keyFilename: "./credentials/serviceAccountKey.json"
});
请注意,如果您使用的是云功能,则 SDK 将使用 Application Default Credentials,因此您不必传递这些参数。简单初始化如下图:
const storage = new Storage()
所以首先我没有提供任何服务帐户,因为我正在使用 firebase 云功能,正如@Dharmaraj 在他的回答中所说
其次,这是google云平台的权限问题,可以通过以下步骤解决
转到项目的 Cloud Console (https://console.cloud.google.com/) > IAM & admin > IAM,找到 App Engine default service account
然后单击最左侧的铅笔 > 单击添加角色 > 在过滤器字段中输入 Service Account Token Creator 并点击保存,一切顺利
从这里找到这个解决方案
https://github.com/firebase/functions-samples/issues/782
我正在努力从云功能上传一张图片 我正在使用 onRequest 将图像从网络发送到云功能。我发送一个 base64 字符串和文件名。现在我正在按照互联网上的不同教程进行操作,但似乎无法解决我的问题。
这是我的代码。我想我在服务帐户 json 上做错了什么。虽然我生成了 json 文件并使用了它,但它仍然不起作用。
当我不使用服务帐户 json 时出现 The caller does not have permission at Gaxios._request
错误
当我使用 serviceAccount.json 然后我得到这个错误 The "path" argument must be of type string. Received an instance of Object
这是来自 file.createWriteStream()
我认为
无论如何,这是代码,任何人都可以帮我解决这个问题
我使用的projectId如下图
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const projectId = functions.config().apikeys.projectid; // In the picture below
const stream = require("stream");
const cors = require("cors")({ origin: true });
const { Storage } = require("@google-cloud/storage");
// Enable Storage
const storage = new Storage({
projectId: projectId, // I did use serviceAccount json here but that wasn't working
});
// With serviceAccount.json code
// const storage = new Storage({
// projectId: projectId,
// keyFilename: serviceAccount,
// });
// This is giving the error of: The "path" argument must be of type string. Received an instance of Object
exports.storeUserProfileImage = functions.https.onRequest((req, res) => {
cors(req, res, async () => {
try {
const bucket = storage.bucket(`gs://${projectId}.appspot.com`);
let pictureURL;
const image = req.body.image;
const userId = req.body.userId;
const fileName = req.body.fileName;
const mimeType = image.match(
/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/
)[1];
//trim off the part of the payload that is not part of the base64 string
const base64EncodedImageString = image.replace(
/^data:image\/\w+;base64,/,
""
);
const imageBuffer = Buffer.from(base64EncodedImageString, "base64");
const bufferStream = new stream.PassThrough();
bufferStream.end(imageBuffer);
// Define file and fileName
const file = bucket.file("images/" + fileName);
bufferStream
.pipe(
file.createWriteStream({
metadata: {
contentType: mimeType,
},
public: true,
validation: "md5",
})
)
.on("error", function (err) {
console.log("error from image upload", err.message);
})
.on("finish", function () {
// The file upload is complete.
console.log("Image uploaded");
file
.getSignedUrl({
action: "read",
expires: "03-09-2491",
})
.then((signedUrls) => {
// signedUrls[0] contains the file's public URL
console.log("Signed urls", signedUrls[0]);
pictureURL = signedUrls[0];
});
});
console.log("image url", pictureURL);
res.status(200).send(pictureURL);
} catch (e) {
console.log(e);
return { success: false, error: e };
}
});
});
const storage = new Storage({
projectId: projectId
keyFilename: "" // <-- Path to a .json, .pem, or .p12 key file
});
keyFilename
接受存储您的服务帐户的路径和凭据本身。
folder
|-index.js
|-credentials
|-serviceAccountKey.json
如果你的目录结构看起来像那么路径应该是这样的:
const storage = new Storage({
projectId: projectId
keyFilename: "./credentials/serviceAccountKey.json"
});
请注意,如果您使用的是云功能,则 SDK 将使用 Application Default Credentials,因此您不必传递这些参数。简单初始化如下图:
const storage = new Storage()
所以首先我没有提供任何服务帐户,因为我正在使用 firebase 云功能,正如@Dharmaraj 在他的回答中所说 其次,这是google云平台的权限问题,可以通过以下步骤解决
转到项目的 Cloud Console (https://console.cloud.google.com/) > IAM & admin > IAM,找到 App Engine default service account
然后单击最左侧的铅笔 > 单击添加角色 > 在过滤器字段中输入 Service Account Token Creator 并点击保存,一切顺利
从这里找到这个解决方案 https://github.com/firebase/functions-samples/issues/782