谷歌云功能在访问实时数据库时返回 204 状态

Posted

技术标签:

【中文标题】谷歌云功能在访问实时数据库时返回 204 状态【英文标题】:Google cloud function returning 204 status when accessing realtime database 【发布时间】:2018-08-10 16:46:25 【问题描述】:

我有一个通过 firebase 托管的用于测试目的的网站,将客户端信息存储在需要稍后访问的实时数据库中。当我通过带有访问我的实时数据库的脚本的单个 html 文档执行此操作时,我能够成功找到信息,但是当我将相同的逻辑复制并粘贴到云函数中时,它不起作用。我已经尝试了我能想到的一切,现在当我运行该函数时,它会执行两次(我不知道为什么)。第一次执行以 http 204 状态结束(未找到内容)。第二次执行返回 http 500 内部服务错误。当我检查 firebase 上的日志时,它说错误是因为“accounts.getValue() 不是函数”。我认为发生的事情是在第一次执行时,该函数无法找到帐户,并且在没有尝试找到帐户的情况下再次执行,这可能是它无法运行 accounts.getValue()

的原因

我想我的主要问题是为什么我的函数无法找到帐户?

geturl 是我遇到问题的函数

我的实时数据库的结构是 数据库名称

-accounts

  -some data

  -more data

  -more account data
-ActiveQRs
  -some data...

我的云函数 index.js 文件是

const functions = require('firebase-functions');
const express = require('express');

const cors = require('cors')(origin: true);

var firebase = require("firebase");


var admin = require("firebase-admin");

require("firebase/auth");
require("firebase/database");
//require("firebase/firestore");
//require("firebase/messaging");
require("firebase/functions");


var serviceAccount = require("./serviceKey.json");


// Initialize the app with a service account, granting admin 
//privileges
admin.initializeApp(
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://databaseName.firebaseio.com"
);

const displayqr = express();
const geturl = express();


displayqr.get('/displayqr', (request, response) => 
    console.log("response sent");
        response.send("testio/qrdisplay.html");
    );




 exports.displayqr = functions.https.onRequest(displayqr);



 exports.geturl = functions.https.onCall((email) => 

    const mail = email.toString();
    var result = "";
    result = result + mail;
       var accounts = 
admin.database().ref("livsuiteform/accounts");
       result = (accounts.getValue());
       accounts.orderByKey().on("value", function(snapshot) 
          snapshot.forEach(function(data) 
            if (data.child("Email").val() == mail) 
              var firstName = data.child("FirstName").val();
              var lastName = data.child("LastName").val();
              result = firstname;
              result = "if loop entered";
               // end if
         //     return "name not found";
              ); // end for each
          ); // end order by
       return result; 
    );

【问题讨论】:

PS 我希望此函数在从外部网站调用时读取数据库日期,而不是在数据库写入或任何其他类型的事件中 您是否从控制台中的 firebase 获取快照数据? 在网站控制台上没有显示任何内容,因为该功能正在服务器上运行,但在 firebase 日志中我没有看到任何消息日志,我无法在任何地方查看console.log,这就是为什么我的结果是一个字符串,最终我希望它返回一个url,但我一直在返回我的结果并将其用作调试控制台 当我执行 result = snapshot.getValue(); 时,我无法看到快照数据 【参考方案1】:

TLDR;关注tutorial,了解如何为您的移动应用构建和部署可调用函数。

您的功能无法按预期工作的原因有多种。

    您将包含 Firebase 的客户端版本 (var firebase = require("firebase");)。您不应该使用甚至不需要客户端版本。相反,只需使用 Firebase 管理员 (docs) 来访问任何数据。如果您在从 Admin SDK 访问数据库时需要某些用户权限,here 是一个很好的例子来说明如何实现这一点(向下滚动到“您仍然可以执行用户授权的更改...”)。 您混合了不同的 Admin SDK 引用。 getValue() 是 Java 管理 SDK 的一部分。您应该使用等效的 javascript val()。此外,在您的代码中,accountsReference 而不是 DataSnapshot。 您没有返回您的Promise。这可能是您以后函数执行不一致的原因SO Question。 您没有从初始函数返回任何内容。如果您不返回任何内容,那么您的应用程序将不会返回任何内容。解决方法同3的解决方法:返回你的Promise。 您不应在 Firebase 函数中使用 on。你应该使用once。不同之处在于 on 不会返回 Promiseonce 会。它返回一个用于分离监听器的函数。

我知道这是很多要点并指出您的代码中的问题,但我只是不想给出一个肤浅的答案,这导致您又问了一个问题并等待了大约 2 个小时(在撰写本文时) 的答案。

我希望这会有所帮助!

代码

exports.geturl = functions.https.onCall((email) => 

  const mail = email.toString();
  var result = "";
  result = result + mail;
  var accounts = admin.database().ref("livsuiteform/accounts");
  return accounts.orderByKey().once("value")
    .then(function (snapshot) 
      snapshot.forEach(function (data) 
        if (data.child("Email").val() == mail) 
          var firstName = data.child("FirstName").val();
          var lastName = data.child("LastName").val();
          result = firstName;
          result = "if loop entered";
         // end if
        //     return "name not found";
      ); // end for each
      return result;
    ); // end order by
);

【讨论】:

感谢 Bryan,这对我有帮助,我想我仍然很难处理承诺,哪些代码行需要承诺,我该如何返回?我用一次替换,但我的函数仍然执行两次,并且运行应该非常快时需要大约 2 秒 @DHolthaus 我添加了一些应该让它正常运行的代码。 geturl 应该与上面的类似。我建议浏览我链接的教程。 我认为现在看起来几乎完全像我的代码,但它仍然没有从数据库中检索信息,我不确定为什么。现在,当我调用该函数时(现在我的应用程序将函数的结果记录到控制台)它返回使用的电子邮件,这意味着结果 = 结果 + 邮件;工作,但其他陈述没有。现在在 firebase 日志中,我的函数每次调用都会运行 3 次,第三次调用会返回一个错误,指出未定义名字。 我浏览了这个教程,但它主要是在客户端,我没有看到太多关于 Promise 的内容,你能告诉我你做了什么改变吗?我能看到的唯一变化是改为一次并使用 .then @DHolthaus 我改变了很多。我通过返回 accounts.orderByKey()... 返回了 Promise。我修复了firstnamefirstName 不同。我删除了函数return result; 末尾的返回。如果您复制/粘贴我提供的代码,您应该会看到结果将是 emailfirstName

以上是关于谷歌云功能在访问实时数据库时返回 204 状态的主要内容,如果未能解决你的问题,请参考以下文章

谷歌云功能完成状态:“连接错误”

如何将流量转发到谷歌云运行中的特定网址?

谷歌云消息传递 GCM 可靠吗?

从谷歌云存储获取状态 503

通过 FS Crawler (elasticsearch) 访问谷歌云存储桶

Ticketek将MongoDB Atlas与谷歌云相结合, 助力分析应用