【问题标题】:Firebase Admin SDK global app initialization in Node.jsNode.js 中的 Firebase Admin SDK 全局应用初始化
【发布时间】:2020-04-30 18:13:30
【问题描述】:

我正在构建一个 Express.js 应用,将 Firebase Admin SDK 用于 ID 令牌验证和 Cloud Firestore 访问等多项功能。在我的主 app.js 文件中,我将应用程序初始化为:

const admin = require('firebase-admin')

const serviceAccount = require('../config/account-credentials.json')
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://databaseurl.firebaseio.com'
})

在另一个文件中,我所做的只是导入:

const admin = require('firebase-admin')

我可以致电admin.auth().verifyIdToken 并验证 ID 令牌就好了。但是,当我打电话给app.database() 时,它抱怨应用程序从未初始化。再次初始化应用会产生一个新的错误提示:

默认 Firebase 应用已存在。这意味着您多次调用 initializeApp() 而不提供应用程序名称作为第二个参数。在大多数情况下,您只需要调用一次 initializeApp()。但是,如果您确实要初始化多个应用程序,请将第二个参数传递给 initializeApp() 以给每个应用程序一个唯一的名称。

我是否需要创建多个具有不同名称的应用才能使其正常工作?或者我如何在整个项目中使用一个应用程序。

【问题讨论】:

标签: node.js firebase firebase-realtime-database firebase-admin


【解决方案1】:

您应该只初始化一次应用程序,然后重新使用该引用。有多种方法可以做到这一点,但我更喜欢的方法是将firebase.ts(初始化 Firebase 应用程序和服务)导入我的index.ts(或任何你的入口点)。然后我传递对需要特定服务的任何其他文件的引用。我使用的是 TypeScript,所以如果你使用的是 vanilla JS,请根据需要进行调整。

firebase.ts

import * as admin from 'firebase-admin';

// Initialize our project application
admin.initializeApp();

// Set up database connection
const firestoreDb: FirebaseFirestore.Firestore = admin.firestore();
firestoreDb.settings({ timestampsInSnapshots: true });
export const db = firestoreDb;

我的 index.ts 文件将导入它:

import { db } from './firebase';

然后,当我使用 Express 设置路由时,我会将每个路由放在另一个文件中,并具有自己的功能。然后将 db 引用传递给任何需要它的对象。

  app
    .route('events')
    .get((req: Request, res: Response) => {
      get_events(db, res);
      return;
    });

这是一篇博文,我对此进行了更多解释:

https://medium.com/@jasonbyrne/how-to-structure-a-serverless-rest-api-with-firebase-functions-express-1d7b93aaa6af

如果您不喜欢依赖注入方法,或者更喜欢只延迟加载您需要的服务,您可以换一种不同的方式。在该方法中,您将拥有您的firebase.js 文件(或任何您称之为的文件),您可以将其导入到任何需要它的页面并调用一个函数来加载该服务。这里我只是在做 Firestore,但你可以创建类似的函数来引用其他服务。

只是将其作为示例输入...

import * as admin from 'firebase-admin';

// Initialize our project application
admin.initializeApp();

// Database reference, not yet loaded
let db: FirebaseFirestore.Firestore | null = null;

// Get cached db reference or create it
export function getDatabaseReference() {
    if (db === null) {
        db = admin.firestore();
    }
    return db;
}

我希望这会有所帮助。如果您有任何问题,请告诉我。

【讨论】:

  • 不能在模块外使用导入...如何解决这个问题
【解决方案2】:

我使用 global 在 cloudRun 的微服务 API 中很好地完成了这项工作。

const admin = require('firebase-admin');
global.GeoFirestore = require('geofirestore').GeoFirestore;

admin.initializeApp({
  credential: admin.credential.applicationDefault()
});

global.db = admin.firestore();
global.admin = admin;

在另一个模块中我可以访问集合:

var docRef = db.collection("collection").doc(doc.id);
    docRef.update({state}).then((doc) => {
        console.log(doc)
    }).catch((error) => {
        console.log("Error getting document:", error);
    });

为了在 GeoFirestore GeoPoint 上工作,我需要全局管理员:

const geofirestore = new GeoFirestore(db);
const geocollection = geofirestore.collection('bin');
var objectToBeStored = {
   ...data,
   coordinates: new admin.firestore.GeoPoint(coordinates.lat, coordinates.lng)
}
geocollection.add(objectToBeStored ).then((docRef) => {
    console.log(`added data: ${docRef.id}`);
}).catch((error) => {
    console.log(`error: ${error}`);
})

【讨论】:

    【解决方案3】:

    我是这样做的:我围绕我需要的 admin.firestore() 等函数创建了一个包装器,然后将其导入并在所有其他函数中使用它:

    FunctionsShared.ts

    import * as functions from 'firebase-functions';
    import * as admin from 'firebase-admin';
    
    admin.initializeApp(functions.config().firebase);
    
    export const FunctionsShared = {
      firestore: () => admin.firestore()
    };
    

    MyFirebaseFunction.ts

    import * as functions from 'firebase-functions';
    import * as admin from 'firebase-admin';
    import {FunctionsShared} from './FunctionsShared';
    
    export getStaleDocumentsQuery = functions.https.onCall(() => {
      // Use FunctionsShared.firestore() instead of admin.firestore()
      return FunctionsShared.firestore()
        .collection('mirror')
        .where('updated', '<', oneMonthAgo)
        .orderBy('updated')
        .limit(limit);
    }
    
    

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 2021-07-19
      • 2021-05-17
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多