firebase - 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
这是警告:
有时这些功能工作得很好:
我尝试在类初始化之前初始化配置,如下所示:
但是再给我一个错误:
在这个新版本中,凭证似乎不是“全局”的。在这种情况下我能做什么?可以使用“全局”实例吗?我很感激任何帮助。谢谢你。
解决方案
归根结底,您遇到的问题并不是问题的原因,而是云功能生命周期管理不当的症状。为了理解我的意思,我将简要介绍正在发生的事情。
与流行的看法相反,虽然admin.initializeApp();
是同步的代码行,但它启动了一个异步过程,使其为以后使用做好准备。
当您调用 时initializeApp()
,它会解析您传递给它的配置对象,或者它从环境变量中组装GOOGLE_APPLICATION_DEFAULT
并由FIREBASE_CONFIG
Cloud 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 事件处理程序中,您错误地(基于变量名)通过admin
ascontext
而不是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);
推荐阅读
- java - 有没有办法在使用 WS-SecurityPolicy 方法时添加 WSS4J 拦截器来签署 SOAP 请求?
- css - 页脚作为视差
- c# - 从文本框中计算整数中的数字,除了“0”
- sql - 什么时候应该使用子连接
- ios - 是否可以在 Decodable 模型中声明泛型
- alibaba-cloud - How to get instances configuration deployed in Ali cloud?
- python - 如何将参数从 TRY 传递到 EXCEPT
- java - 如何克隆 java 密钥库实例?
- testing - In what order does beforeEach and beforeAll execute?
- c# - Automapper 如果源为空,则设置目标对象属性