首页 > 解决方案 > Firebase 函数不会在不同的类上初始化管理员

问题描述

我有一个几天前运行良好的 ionic 3 应用程序。应用程序在触发“onWrite”后从实时数据库接收来自 FCM 的通知。

Firebase 函数 npm 包已过时,因此我使用以下命令进行了更新:

npm install --save firebase-functions@latest

现在,控制台向我显示一条警告,说我的管理员使用了错误的凭据。我的代码有一些类,每个类都有一个管理实例。“主”管理员在 index.js 上初始化:

'use strict';
const functions = require('firebase-functions');

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

const serviceController = require('./controllers/serviceController');


exports.notifyWorks = functions.database.ref('/notificationsAll/{State_}/{notificationYear}/{notificationMonth}/{notificationId}')
    .onWrite((change, context) => {            
      return serviceController.notifyWorks(change, admin)      
});

' serviceController ' 类构造函数:

class serviceController {  

  constructor() {

    this.admin = require('firebase-admin');
    this.notificationIcon = ''
    this.notificationSound = "ding"
      
  }
  
  notifyWorks(change, context){

    if (!change.after.exists()) {
  
      return new Promise(function(resolve){
        resolve(console.log("Não foi possível identificar tipo de app"))
      });
  
    } else {
  
      const snapshot = change.after  
      const data = snapshot.val()  
  
      if (!data) {
  
        return new Promise(function(resolve){
          resolve(console.log("Não foi possível identificar os dados da mensagem"))
        });
        
      } else {
     resolve(console.log("Here we continue with the logic"))
       }      
     }    
   }
             
}

exports.notifyWorks = function(change, context){    
  const helper = new serviceController();
  return helper.notifyWorks(change, context)
};

函数 package.json:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint --init .",
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "babel-eslint": "^10.0.1",
    "exceljs": "^3.9.0",
    "firebase-admin": "~5.12.0",
    "firebase-functions": "^3.14.1",
    "geolib": "^2.0.24",
    "google-distance-matrix": "^1.1.1",
    "moment": "^2.24.0",
    "moment-range": "^4.0.2",
    "request": "^2.88.0",
    "xml-js": "^1.6.11"
  },
  "devDependencies": {
    "eslint": "^4.12.0",
    "eslint-plugin-promise": "^3.6.0"
  },
  "rules": {},
  "engines": {
    "node": "10"
  },
  "private": true
}

离子信息输出:

离子信息

离子:

离子 CLI:5.4.16 (/usr/local/lib/node_modules/ionic)
离子框架:离子角 3.9.2 @ionic/app-scripts:3.2.3

科尔多瓦:

Cordova CLI:8.1.2 (cordova-lib@8.1.1) Cordova 平台:android 8.1.0 Cordova 插件:cordova-plugin-ionic-webview 1.2.1,(和其他 29 个插件)

效用:

cordova-res(可用更新:0.15.3):0.8.1 本机运行(可用更新:1.4.0):1.3.0

系统:

Android SDK 工具:26.1.1 (/home/diego/Android/Sdk) NodeJS
:v14.17.1 (/home/diego/.nvm/versions/node/v14.17.1/bin/node) npm
:6.14.13 操作系统: Linux 5.4

这是警告:

在此处输入图像描述

有时这些功能工作得很好:

在此处输入图像描述

我尝试在类初始化之前初始化配置,如下所示:

在此处输入图像描述

但是再给我一个错误:

在此处输入图像描述

在这个新版本中,凭证似乎不是“全局”的。在这种情况下我能做什么?可以使用“全局”实例吗?我很感激任何帮助。谢谢你。

标签: firebaseionic-frameworkgoogle-cloud-functions

解决方案


归根结底,您遇到的问题并不是问题的原因,而是云功能生命周期管理不当的症状。为了理解我的意思,我将简要介绍正在发生的事情。

与流行的看法相反,虽然admin.initializeApp();是同步的代码行,但它启动了一个异步过程,使其为以后使用做好准备。

当您调用 时initializeApp(),它会解析您传递给它的配置对象,或者它从环境变量中组装GOOGLE_APPLICATION_DEFAULT并由FIREBASE_CONFIGCloud Functions 预填充的配置对象。

解析配置后,它会在后台使用来自配置对象的凭据开始协商其访问令牌的过程。如果此过程以任何方式失败,您通常会遇到"app/invalid-credential"如下错误:

通过“凭据”属性提供给 initializeApp() 的凭据实现未能获取有效的 Google OAuth2 访问令牌,并出现以下错误:...

当云功能完成其工作主体时,它会被标记为非活动状态,任何资源都会受到严重限制,任何网络请求都可能会被断开或阻塞。本地 Cloud Functions 模拟器不会模拟此行为,因此您应确保在说明您的函数已完成之前完成了 Cloud Functions 需要做的所有工作(通过正确链接 Promises 或仅在一切完成后调用res.end()/ /etc ) res.send().

如果您在其他消息之前看到此日志消息,则表明这种情况正在发生:

函数执行耗时... ms,完成...

重要的是,当处于这种“非活动”状态时,即使是用于协商 Admin SDK 访问令牌的请求也会被中断,从而导致"app/invalid-credential"错误。

怎么修

您需要处理您的notifyWorks函数并查找返回 aPromise您不使用await或返回给调用者的任何函数调用。


首先,我可以在您共享的代码中看到以下几点。

这个 Promise 构造函数调用令人困惑(作为console.log()返回void( undefined)):

return new Promise(function(resolve) {
  resolve(console.log("Não foi possível identificar tipo de app"))
});

应改写为:

console.log("Não foi possível identificar tipo de app")
return Promise.resolve();

或(如果在async函数内部):

console.log("Não foi possível identificar tipo de app")
return;

else接下来,您不必要地使用语句。在您的代码中,您使用以下结构:

if (condition) {
  return "not-exists";
} else {
  if (condition) {
    return "falsy-data";
  } else {
    return "done-stuff";
  }
}

这可以展平为:

if (condition) {
  return "not-exists";
}

if (condition) {
  return "falsy-data";
}

return "done-stuff";

如果您正在检查change.after.exists(),则无需检查是否data是虚假的,如果您只检查它是否是虚假的null

function notifyWorks(change, context)
if (!change.after.exists()) {
  console.log("Os dados foram excluídos, abortados.")
  return;
}

// data won't be `null`
const data = change.after.val();

console.log("Here we continue with the logic")
// do stuff

接下来,在您的 HTTP 事件处理程序中,您错误地(基于变量名)通过adminascontext而不是context.

exports.notifyWorks = functions.database.ref('/notificationsAll/{State_}/{notificationYear}/{notificationMonth}/{notificationId}')
    .onWrite((change, context) => {            
      return serviceController.notifyWorks(change, admin)      
});

应该

exports.notifyWorks = functions.database.ref('/notificationsAll/{State_}/{notificationYear}/{notificationMonth}/{notificationId}')
    .onWrite((change, context) => {            
      return serviceController.notifyWorks(change, context)      
});

或者也可以写成

exports.notifyWorks = functions.database.ref('/notificationsAll/{State_}/{notificationYear}/{notificationMonth}/{notificationId}')
    .onWrite(serviceController.notifyWorks);

推荐阅读