Firebase Promises Issue - «Превышен максимальный размер стека вызовов» - PullRequest
0 голосов
/ 09 сентября 2018

У меня проблема с Callable Functions. Вот моя функция Firebase:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request-promise');

admin.initializeApp(functions.config().firebase);

exports.phoneAuthRequest = functions.https.onCall((data, context) => {
  // Message text passed from the client.
  const text = data.text;

  // Authentication / user information is automatically added to the request.
  const uid = context.auth.uid;
  const phone = context.auth.token.phone_number;

  const url = "https://api.authy.com/protected/json/phones/verification/start?api_key=<key here>&via=sms&country_code=1&phone_number=" + phone;
  const httpReq = {
    uri: url,
    method: 'POST',
    json: true,
    resolveWithFullResponse: true
  };

  return new Promise((resolve, reject) => {
    request(httpReq).then((response) => {
      // Twillio request returned with success
      console.log("response: " + JSON.stringify(response));
      return resolve(response);
    }).catch(function(error) {
      console.log("error: " + JSON.stringify(error));
      return reject(error);
    });  
  });
});

А вот мой пример клиента:

<html>
  <head>
    <script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-database.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.4.2/firebase-functions.js"></script>

    <script>
      var config = { <firebase configuration in here> };
      firebase.initializeApp(config);

      function myTest() {
        var display = document.getElementById('display');
        display.innerHTML = "Started";

        var auth = firebase.auth();
        auth.signInWithEmailAndPassword(<username>,<password>).then(function(authResult) {
          display.innerHTML = "Signed in";

          var phoneAuthRequest = firebase.functions().httpsCallable('phoneAuthRequest');
          phoneAuthRequest({'text': 'Test'}).then(function(result) {
            display.innerHTML = JSON.stringify(result);
          }).catch(function(error) {
            display.innerHTML = JSON.stringify(error);
          });
        }).catch(function(error) {
          display.innerHTML = "Login failure.  Your email or password could not be validated.  " + JSON.stringify(error);
        });
      }
    </script>
  </head>

  <body>
    <input type="submit" value="Test It" data-wait="Loading..." id="loginBtn" class="login-window-login-btn w-button" onclick="myTest();">
    <div id="display"></div>
  </body>
</html>

Проверка этой кодовой комбинации показывает, что вызывается функция Firebase 'phoneAuthRequest', которая, в свою очередь, отправляет запрос Twillio, и ответ от Twillio возвращается правильно в ответ, но в журналах консоли отображается эта ошибка:

Unhandled error RangeError: Maximum call stack size exceeded
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13395:23)
    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:13400:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399: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:13400:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399: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:13400:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399: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:13400:38
    at /user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:4925:15
    at baseForOwn (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:3010:24)
    at Function.mapValues (/user_code/node_modules/firebase-functions/node_modules/lodash/lodash.js:13399:7)
    at encode (/user_code/node_modules/firebase-functions/lib/providers/https.js:242:18)

И, конечно же, ответ клиенту:

{"code":"internal"}

Когда я читал похожие посты, совет заключался в том, чтобы сериализовать обещания, которые я не уверен, что полностью понимаю, как это сделать, или, чтобы обернуть асинхронный вызов (запрос в этом случае) внутри нового обещания, которое я и сделал, и оно все еще не работает.

Если вы собираетесь ответить на этот вопрос, не могли бы вы конкретно рассказать о предлагаемом решении, приведя пример кода?

Заранее спасибо ...

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Хорошо, я решил эту проблему с кучей ударов головой о стену. Вот код:

exports.phoneAuthRequest = functions.https.onCall((data, context) => {
  // Example of using context to obtain the user information about the calling user
  const uid = context.auth.uid;
  // Example of obtaining a paramter that was passed by the calling function
  const phone = data.phone;
  const e164 = "+1" + phone;

  httpReq = ...

  // Example of a return if you have not yet made a call to an asynchonous function.
  return ({'status': 'success'});

  // Here is an example of a nested set of asynchonous calls and how to return from them.
  return admin.auth().updateUser(uid, {'phoneNumber': e164}).then(function(userRecord) {
    // the Phone Number was updated
    return request(httpReq).then((response) => {
      var updates = {};
      updates['/users/' + uid + "/centralVerified"] = false;
      return database.ref().update(updates).then(function(rslt) {
        return Promise.resolve({'status': 'success');
      }).catch(function(error) {
        return Promise.reject({'status': 'failed'});
      });
    }).catch(function(error) {
      return Promise.reject({'status': 'failed'});
    });
  }).catch(function(error) {
    return Promise.reject({'status': 'failed'});
  });
});

Обратите внимание, что есть два разных способа возврата из вызываемой функции. Если вы не делали асинхронных вызовов, вы можете просто возвращать значения, но если вы вызвали асинхронную функцию, вы должны вернуть обещание. Если вы ищете Отклонить или Разрешить в вызывающей подпрограмме, предполагается, что возвращаемое значение является Решением.

Надеюсь, это поможет другим ... Желаю удачи!

0 голосов
/ 10 сентября 2018

Попробуйте удалить клиента и вызвать функцию Firebase через curl.

Вызов функций через HTTP-запросы

...