You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js后端多Firebase项目初始化失败问题及解决方案

多Firebase项目应用信息API搭建问题与解决方案

问题背景

我在多个Firebase项目下拥有大量应用,希望获取这些应用的信息以便后续更新,因此决定用Node.js搭建API,实现从不同项目中获取信息(例如统计特定项目的应用数量)。已下载每个项目的Service Account密钥,核心实现逻辑如下:

原实现代码

控制器代码

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);

问题现象

启动Express后,首次调用http://localhost:99/projects/project-name/apps可成功获取数据,但切换为其他项目(如http://localhost:99/projects/project-name-2/apps)时调用失败,原因是未指定应用实例就初始化了firebase-admin。尝试过调整require时机、工厂函数等多种方式均未解决,虽已缓存项目避免重复初始化,但跨项目调用仍异常。

解决方案

samthecodingman提供的方案完美解决问题,调整后的完整代码如下:

调整后的控制器代码

// Should return the list of apps id for this project
async function getAllApps(req, res) {
  const projectId = req.params.projectId;

  const project = getFirebaseAdminForProject(projectId);
  const projectManagement = getProjectManagement(project);

  try {
    androidApps = await projectManagement.listAndroidApps();
    iosApps = await 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' });
  }
}

核心工具函数

const { initializeApp, getApps, cert } = 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
        ? `${process.env.FIREBASE_ACCOUNT_SERVICE_PATH}\\${projectId}.json`
        : `C:\\path\\to\\${projectId}.json`;

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

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

module.exports = {
    getFirebaseAdminForProject
};

关键说明

  • 无需再用Map缓存项目,firebase-admin内部已实现缓存机制
  • 核心要点是理解firebase-admin中的App即对应项目实例,初始化时需传入projectId作为实例名称,以此区分不同项目
  • 修复了原代码中!== null的判断问题,改用!= null更合理(可同时判断null和undefined)

内容的提问来源于stack exchange,提问作者Joao Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:25:07