在后端 Javascript 中处理多个 Firebase 项目

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

我在许多项目中有许多应用程序,我想获取有关它们的信息以便稍后更新它们,因此我决定使用 NodeJS 创建一个 API,并配置我的端点从不同项目检索信息的方式,例如计数特定项目中的应用程序的数量,我知道每个项目都需要服务帐户密钥,并且我已经下载了它们,所以我的核心逻辑是这样的端点

const { initProject } = require('../config/firebaseConfig')
async function getAllApps(req, res) {
  const projectId = req.params.projectId;
  const project = await initProject(projectId);

  try {
    androidApps = await project.projectManagement().listAndroidApps();
    iosApps = await project.projectManagement().listIosApps();

    const allApps = [...androidApps, ...iosApps];

    const appList = allApps.map((app) => ({
      appId: app.appId
    }));

    res.status(200).json(appList);

  } catch (error) {
    console.error('Error retrieving apps:', error);
    res.status(500).json({ error: 'Failed to retrieve apps for the project' });
  }
}

initProject 是

const admin = require('firebase-admin');

// Initialize a project cache
const projectCache = new Map();

//initialize the project based on it's id name
async function initProject(projectId) {
    // Check if the project has already been initialized
    if (projectCache.has(projectId)) {
        return projectCache.get(projectId);
    }

    try {
        // Construct the path to the service account key file using the provided path or a default value
        if (process.env.FIREBASE_ACCOUNT_SERVICE_PATH !== null) {
            var serviceAccountPath = `${process.env.FIREBASE_ACCOUNT_SERVICE_PATH}\\${projectId}.json`;
        } else {
            var serviceAccountPath = `C:\\path\\to\\cred\\${projectId}.json`;
        }

        // Initialize the Firebase Admin SDK
        const serviceAccount = require(serviceAccountPath);

        admin.initializeApp({
            credential: admin.credential.cert(serviceAccount),
            databaseURL: `https://${projectId}.firebaseio.com`,
        });

        // Get the initialized Firebase project
        const firebaseProject = admin;

        // Cache the initialized project
        projectCache.set(projectId, firebaseProject);

        return firebaseProject;

    } catch (error) {

        console.error('Error initializing Firebase project: ', error);
        throw new Error('Failed to initialize Firebase project');
    }
}

module.exports = {
    initProject
}

路线是这样的

router.get('/:projectId/apps', projectController.getAllApps);

所以我也启动了快递,对第一个端点的调用是这样的

http://localhost:99/projects/project-name/apps
所以它工作得很好我的第一次调用结果成功并且我可以收到我需要的东西但是如果我尝试再次调用这个端点但使用另一个项目
http://localhost:99/projects/project-name-2/apps
它会失败,因为我已经初始化了firebase-admin而不指定应用程序,但我的需求正是这样,例如计算每个项目的应用程序数量,所以我需要初始化它,我已经尝试更改此设置以在我像这样退出 firebaseConfig 后立即终止需求

// Initialize a project cache
const projectCache = new Map();

// Function factory to create a new Firebase App instance
function createFirebaseApp(projectId) {
    return () => {
        if (projectCache.has(projectId)) {
            const cachedProject = projectCache.get(projectId);
            return cachedProject;
        }

        try {
            // Construct the path to the service account key file using the provided path or a default value
            if (process.env.FIREBASE_ACCOUNT_SERVICE_PATH !== null) {
                var serviceAccountPath = `${process.env.FIREBASE_ACCOUNT_SERVICE_PATH}\\${projectId}.json`;
            } else {
                var serviceAccountPath = `C:\\EscolarManager\\Dados\\AppsCred\\${projectId}.json`;
            }

            // Initialize a new Firebase Admin SDK for each project
            const admin = require('firebase-admin');
            const serviceAccount = require(serviceAccountPath);

            const firebaseProject = admin.initializeApp({
                credential: admin.credential.cert(serviceAccount),
                databaseURL: `https://${projectId}.firebaseio.com`,
            });

            // Cache the initialized project
            projectCache.set(projectId, firebaseProject);

            return firebaseProject;
        } catch (error) {
            console.error('Error initializing Firebase project: ', error);
            throw new Error('Failed to initialize Firebase project');
        }
    }
}

module.exports = {
    createFirebaseApp
}

我也尝试过制作工厂功能

const admin = require('firebase-admin');

// Initialize a project cache
const projectCache = new Map();

// Function factory to create a new Firebase App instance
function createFirebaseApp(projectId) {
    return () => {
        if (projectCache.has(projectId)) {
            const cachedProject = projectCache.get(projectId);
            return cachedProject;
        }

        try {
            // Construct the path to the service account key file using the provided path or a default value
            if (process.env.FIREBASE_ACCOUNT_SERVICE_PATH !== null) {
                var serviceAccountPath = `${process.env.FIREBASE_ACCOUNT_SERVICE_PATH}\\${projectId}.json`;
            } else {
                var serviceAccountPath = `C:\\EscolarManager\\Dados\\AppsCred\\${projectId}.json`;
            }

            // Initialize the Firebase Admin SDK without specifying an app name
            const serviceAccount = require(serviceAccountPath);

            const firebaseProject = admin.initializeApp({
                credential: admin.credential.cert(serviceAccount),
                databaseURL: `https://${projectId}.firebaseio.com`,
            });

            // Cache the initialized project
            projectCache.set(projectId, firebaseProject);

            return firebaseProject;
        } catch (error) {
            console.error('Error initializing Firebase project: ', error);
            throw new Error('Failed to initialize Firebase project');
        }
    }
}

// Example usage of the factory to create new Firebase App instances
const projectFactory = createFirebaseApp('project1');

const app1 = projectFactory();
const app2 = projectFactory();

console.log(app1 === app2); // This should print false, indicating they are different instances

但是它们都不起作用,结果相同。我正在缓存项目,以便不需要两次初始化同一个项目,但调用不同的项目是我的问题

javascript node.js firebase express firebase-admin
1个回答
0
投票

根据您的代码,您可能不知道 Firebase SDK 能够初始化多个应用实例。当您调用

initializeApp
而不提供实例名称时,您将初始化默认实例。在上面的代码中,您多次调用
admin.initializeApp(config)
,然后尝试将
admin
作为初始化项目存储到字典中。对同一个实例调用
initializeApp
会抛出异常,并且
admin
只是 SDK 的命名空间,它并不代表您刚刚初始化的应用程序(从
initializeApp
返回的值是,正如您在第二次尝试中意识到的那样) .

注意: 只需要一个 Admin SDK 实例即可与该项目上的所有资源进行通信,为同一项目初始化多个实例是多余的。这里的“应用程序”不是指 iOS/Android/Web 应用程序,而是一个初始化的 admin SDK 实例。

考虑到这一点,您可以将代码更新为:

// ./firebase.js
const { initializeApp, getApps } = require('firebase-admin/app');

function getFirebaseAdminForProject(projectId) {
  if (!projectId)
    throw new Error('Project ID is required!');

  let projectApp = getApps().find(app => app.name === projectId);

  if (projectApp)
    return projectApp;

  // if here, project is not yet initialized
  let serviceAccountPath = process.env.FIREBASE_ACCOUNT_SERVICE_PATH != null // <- note != instead of !==
    ? `${process.env.FIREBASE_ACCOUNT_SERVICE_PATH}\\${projectId}.json`
    : `C:\\path\\to\\${projectId}.json`;

  return initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: `https://${projectId}.firebaseio.com`
  }, projectId); // <-- using projectId as instance name
}

exports.getFirebaseAdminForProject = getFirebaseAdminForProject;
exports.project1App = getFirebaseAdminForProject('project-1');
exports.project2App = getFirebaseAdminForProject('project-2');

要获取给定应用程序的 Firestore,您可以使用:

const { getApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');

const db = getFirestore(getApp('project-1'));

const { project1App } = require('./firebase');
const { getFirestore } = require('firebase-admin/firestore');

const db = getFirestore(project1App);

考虑将 require/exports 切换为现代导入/导出等效项。

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