最后,我找到了答案的解决方案。解决方案是使用 Cloud Functions。
Cloud Functions 允许我们在作为我们 firebase 项目的一部分的 nodejs 环境中创建端点并使用 AdminSdk。使用这种方法,我们可以向该端点发送一个 http 请求,这将检查接收到的带有请求的令牌是否有效,如果有效,则保存文件。
这是功能代码:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const path = require("path");
const os = require("os");
const fs = require("fs");
const Busboy = require("busboy");
// Follow instructions to set up admin credentials:
// https://firebase.google.com/docs/functions/local-emulator#set_up_admin_credentials_optional
admin.initializeApp({
credential: admin.credential.cert(
__dirname + "/path/to/cert.json"
),
storageBucket: "bucket-name",
});
const express = require("express");
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const authenticate = async (req, res, next) => {
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith("Bearer ")
) {
res.status(403).send("Unauthorized");
return;
}
const idToken = req.headers.authorization.split("Bearer ")[1];
try {
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
req.user = decodedIdToken;
next();
return;
} catch (e) {
res.status(403).send("Unauthorized");
return;
}
};
app.use(authenticate);
// POST /api/messages
// Create a new message, get its sentiment using Google Cloud NLP,
// and categorize the sentiment before saving.
app.post("/test", async (req, res) => {
const busboy = new Busboy({ headers: req.headers });
const tmpdir = os.tmpdir();
// This object will accumulate all the fields, keyed by their name
const fields = {};
// This object will accumulate all the uploaded files, keyed by their name.
const uploads = {};
// This code will process each non-file field in the form.
busboy.on("field", (fieldname, val) => {
// TODO(developer): Process submitted field values here
console.log(`Processed field ${fieldname}: ${val}.`);
fields[fieldname] = val;
});
const fileWrites = [];
// This code will process each file uploaded.
busboy.on("file", (fieldname, file, filename) => {
// Note: os.tmpdir() points to an in-memory file system on GCF
// Thus, any files in it must fit in the instance's memory.
console.log(`Processed file ${filename}`);
const filepath = path.join(tmpdir, filename);
uploads[fieldname] = filepath;
const writeStream = fs.createWriteStream(filepath);
file.pipe(writeStream);
// File was processed by Busboy; wait for it to be written.
// Note: GCF may not persist saved files across invocations.
// Persistent files must be kept in other locations
// (such as Cloud Storage buckets).
const promise = new Promise((resolve, reject) => {
file.on("end", () => {
writeStream.end();
});
writeStream.on("finish", resolve);
writeStream.on("error", reject);
});
fileWrites.push(promise);
});
// Triggered once all uploaded files are processed by Busboy.
// We still need to wait for the disk writes (saves) to complete.
busboy.on("finish", async () => {
await Promise.all(fileWrites);
// Process saved files here
for (const file in uploads) {
admin.storage().bucket().upload(uploads[file], function(err, file) {
if (err) {
res.status(403).send("Error saving the file.");
}
res.status(201).send("Saved");
});
}
});
busboy.end(req.rawBody);
});
exports.api = functions.https.onRequest(app);