【问题标题】:Firebase Unhandled error RangeError: Maximum call stack size exceededFirebase未处理的错误RangeError:超出最大调用堆栈大小
【发布时间】:2019-03-04 19:21:28
【问题描述】:

我正在调用 Firebase 可调用函数,并返回 Firebase 指定的承诺,但我收到此错误:

未处理的错误 RangeError: 超出最大调用堆栈大小

代码如下:

exports.getProductInfo = functions.https.onCall((data, context) => {
  // Message text passed from the client.
  const product = data.product;
  // Authentication / user information is automatically added to the request.
  // const uid = context.auth.uid;

  // Get the current Server Timestamp
  var ts = String(Date.now());
  var key, snap, node;

  // Get the price of the specified product
  return database.ref('/products/' + product)
                 .orderByKey()
                 .endAt(ts)
                 .limitToLast(1)
                 .once('value', function (snapshot) {
                   snap = snapshot.val();
                   console.log('snap: ' + JSON.stringify(snap));

                   key = Object.keys(snap)[0];
                   node = snap[key];
                   console.log('node: ' + JSON.stringify(node));

                   return(node);
                 });
});

这是我在函数日志中看到的输出:

snap: {"1538004276":{"description":"This the Basic product","price":40}}

node: {"description":"This the Basic product","price":40}

Unhandled error RangeError: Maximum call stack size exceeded
    at Object (native)
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4905:24
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:2996:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13401:7)
    at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:242:18)
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13402:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4911:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:2996:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13401:7)
    at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:242:18)
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13402:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4911:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:2996:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13401:7)
    at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:242:18)
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13402:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4911:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:2996:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13401:7)
    at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:242:18)
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13402:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4911:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:2996:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13401:7)

救命!

【问题讨论】:

  • 您的问题几乎与 dup 完全相同。返回实际的原始数据,而不是其中包含循环引用的快照对象。
  • 你能指出你认为回答这个问题的副本吗?解释快照数据如何具有循环引用。我返回的是一个带有两个值的简单对象,如上所述。
  • 问题类似,但我现在已经在答案中说明了具体问题。
  • 这个答案可能对stackoverflow.com/a/66612425/2761641有帮助

标签: firebase google-cloud-functions


【解决方案1】:

问题类似于the one described here。您将返回一个由 Firebase API 生成的复杂对象,称为 DocumentSnapshot。一个快照它本身不是原始的 JSON 数据返回给客户端,它包含对其他对象的循环引用。 Cloud Functions 一直在尝试序列化所有这些对象。相反,只需通过在快照上调用 val() 来返回感兴趣位置数据的原始 JavaScript 对象:

return database
    .ref('/products/' + product)
    .orderByKey()
    .endAt(ts)
    .limitToLast(1)
    .once('value')             // once() returns a promise containing a snapshost
    .then(snapshot => {
        return snapshot.val()  // this is the raw JS object
    })

您通常不会在同一个调用中同时使用返回的承诺回调。使用 Promise 会更容易。

【讨论】:

    【解决方案2】:

    我的解决方案是将 return 包装在 Promise 中:

    exports.getIssue = functions.https.onCall(data => {
    const issueKey = data.issueKey
    
    return new Promise((resolve, reject) => {
        admin
            .database()
            .ref('issue')
            .child(issueKey)
            .once('value', snapIssue => {
                let issue = snapIssue.val()
                if (issue) {
                    return resolve(issue)
                } else {
                    reject('Issue not found')
                }
            })
            .catch(reject)
    })
    

    【讨论】:

      【解决方案3】:

      值得一提的是,这在Firebase doc中并没有明确写;您应该始终在 HTTP 请求之前对对象进行字符串化。在另一端简单地解析它。删除 JSON.stringify() 和 JSON.parse() 将触发完全相同的错误。

      客户端:

      auth.signInWithEmailAndPassword(username, password).then(async (snapShot) => {
          const getToken = await functions.httpsCallable('getToken')(JSON.stringify(snapShot));
          ....
      });
      

      服务器端:

      exports.getToken = functions.https.onCall(async (data, context) => {
          console.log(JSON.parse(data));
          ...
      });
      

      【讨论】:

        猜你喜欢
        • 2021-01-27
        • 2019-01-24
        • 2021-04-06
        • 2021-03-04
        • 1970-01-01
        • 2018-06-03
        • 2021-09-21
        • 2013-07-08
        • 2018-01-24
        相关资源
        最近更新 更多