【问题标题】:Amazon Lambda to Firebase亚马逊 Lambda 到 Firebase
【发布时间】:2016-09-16 11:37:40
【问题描述】:

当我尝试在 Lambda (Node.js 4.3) 中运行它时,我得到“找不到模块 'firebase'”

var Firebase = require('firebase');

当我尝试上传包含 node_modules/firebase 的压缩包时,也会发生同样的情况

有没有人有一个有效的“从 lambda 写到 firebase”的实现?

【问题讨论】:

  • 我遇到了同样的错误。我在我的 aws lamda 函数中写了下面的答案,但是如何添加 firebase 模块或库。请给我提示

标签: lambda firebase amazon


【解决方案1】:

要在 AWS Lambda (Nodejs 4.3) 中安全使用 firebase npm 包(版本 3.3.0),请执行以下操作:

'use strict';

var firebase = require("firebase");

exports.handler = (event, context, callback) => {
    context.callbackWaitsForEmptyEventLoop = false;  //<---Important

    var config = {
        apiKey: "<<apikey>>",
        authDomain: "<<app_id>>.firebaseapp.com",
        databaseURL: "https://<<app_id>>.firebaseio.com",
        storageBucket: "<<app_id>>.appspot.com",
    };

    if(firebase.apps.length == 0) {   // <---Important!!! In lambda, it will cause double initialization.
        firebase.initializeApp(config);
    }

    ...
    <Your Logic here...>
    ...
};

【讨论】:

  • 这解决了我一直在努力解决的问题。你到底是怎么找到这 2 颗宝石来让 firebase 工作的?而且我仍然不太了解第二个 (fireabase.apps.length == 0) - 根据我的日志,它只是 0,但如果我 进行该测试,它就会超时。所以我知道我需要这样做,但我真的很想知道为什么
  • OK - 一些推测(我是 Lambda 新手):context.callbackWaitsForEmptyEventLoop = false 表示调用回调时函数将暂停(但不是“终止”)。但它可能会在 Lambda 世界中徘徊很长一段时间(距离我的测试至少 25 分钟)。如果您在此期间再次调用该函数,它会有效地恢复活力,所有变量都保持其原始值,此时firebase.apps.length == 1,因此无需再次初始化。我接近了吗?
  • 对洪水感到抱歉。最后一个想法。将调用移动到处理程序函数之外的firebase.initializeApp()(根据@paul-richter 的回答)会使这更简单吗?无需测试firebase.apps.length,我的测试表明它仍在使用“冻结”版本 - 第一次调用需要大约 2300 毫秒才能从 firebase 获得结果,但后续调用大约需要 100 毫秒,这表明它们已经过身份验证。
  • 对未来读者的一些观察。我很欣赏这个解决方案(它解决了实际问题)和 REST API 答案(这可能是这个用例的更好选择)。我在 node6.10 Lambda 中测试了两者,我发现管理 SDK 在 0.6-4 秒内假脱机并在热时在 28-90 毫秒内执行。 REST API 在 0.2-0.6 秒内假脱机并在热时在 75-200 毫秒内执行。在获取标量数据库值的简单用例中,SDK 似乎更快(因此更便宜)。 YMMV,但要测试这两种方法。
  • 您可以将firebase.initializeApp 移到处理程序之外。
【解决方案2】:

我通过使用 firebase REST api 解决了我的问题

var https = require('https');

exports.handler = function(event, context, callback) {

    var body = JSON.stringify({
        foo: "bar"
    })

   var https = require('https');

var options = {
  host: 'project-XXXXX.firebaseio.com',
  port: 443,
  path: '/.json',
  method: 'POST'
};

var req = https.request(options, function(res) {
  console.log(res.statusCode);
  res.on('data', function(d) {
    process.stdout.write(d);
  });
});
req.end(body);

req.on('error', function(e) {
  console.error(e);
});

    callback(null, "some success message");

}

【讨论】:

    【解决方案3】:

    这已经晚了,但万一有人在看:

    压缩您的项目文件夹而不是项目文件夹的 contents 可能会导致此问题。解压后的压缩文件夹不应包含包含 lambda 文件的文件夹,而应在根级别包含 index.js 文件和 node_modules 文件夹。

    一个 lambda 函数的工作示例是(使用最新闪亮的 firebase 东西 *sigh*):

    var firebase = require('firebase');
    
    // Your service account details
    var credentials = {
      "type": "service_account",
      "project_id": "project-123451234512345123",
      "private_key_id": "my1private2key3id",
      "private_key": "-----BEGIN PRIVATE KEY-----InsertKeyHere-----END PRIVATE KEY-----\n",
      "client_email": "projectname@project-123451234512345123.iam.gserviceaccount.com",
      "client_id": "1111222223333344444",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://accounts.google.com/o/oauth2/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/projectname%40project-123451234512345123.iam.gserviceaccount.com"
    };
    
    firebase.initializeApp({
      serviceAccount: credentials,
      databaseURL: "https://project-123451234512345123.firebaseio.com"
    });
    
    exports.handler = function (event, context, callback) {
    
      // I use some data passed in from AWS API Gateway:
      if (!event.firebaseUid) {
        callback('Missing param for id');
      }
    
      firebase.database().ref().child('users').child(firebaseUid).child('at').set(newTokens.access_token).then(function (data) {
        console.log('Firebase data: ', data);
        firebase.database().goOffline();
        callback(null, 'Firebase data: ', data);
      }).catch(function (error) {
        callback('Database set error ' + error);
      });
     };
    

    现在要注意了。我经历过这种情况,即使在 firebase 回调发生后,lambda 函数也会超时,即。 set 函数似乎创建了一个侦听器,该侦听器使 lambda 函数保持打开状态,尽管返回了正确的数据。

    更新:调用 firebase.database().goOffline() 修复了我遇到的 Lambda 函数超时问题。

    关于未验证或不适当的安全性的常见警告,以及使用此方法暂停空间和时间的可能性。

    【讨论】:

    • 我目前正在我的本地机器上工作(在 java 脚本中),但我的函数最终也卡住了。 goOffline() 在我的情况下不起作用。你是怎么解决的?
    • 我目前正在我的本地机器上工作(在 java 脚本中),但我的函数最终也卡住了。 goOffline() 在我的情况下不起作用。你是怎么解决的?
    • @josiah-choi 下面的回答为我解决了这个问题 - 请参阅 context.callbackWaitsForEmptyEventLoop = false
    【解决方案4】:

    2017-03-22 编辑:谷歌刚刚宣布了firebase cloud functions,这是一个更好的方法。云函数的工作方式与 lambda 类似,可以从 firebase 事件触发。


    这是我使用the REST api 的解决方案(所以你不需要require 任何东西):

    var https = require('https');
    var firebaseHost = "yourapp.firebaseio.com";
    function fbGet(key){
      return new Promise((resolve, reject) => {
        var options = {
          hostname: firebaseHost,
          port: 443,
          path: key + ".json",
          method: 'GET'
        };
        var req = https.request(options, function (res) {
          res.setEncoding('utf8');
          var body = '';
          res.on('data', function(chunk) {
            body += chunk;
          });
          res.on('end', function() {
            resolve(JSON.parse(body))
          });
        });
        req.end();
        req.on('error', reject);
      });
    }
    
    function fbPut(key, value){
      return new Promise((resolve, reject) => {
        var options = {
          hostname: firebaseHost,
          port: 443,
          path: key + ".json",
          method: 'PUT'
        };
    
        var req = https.request(options, function (res) {
          console.log("request made")
          res.setEncoding('utf8');
          var body = '';
          res.on('data', function(chunk) {
            body += chunk;
          });
          res.on('end', function() {
            resolve(body)
          });
        });
        req.end(JSON.stringify(value));
        req.on('error', reject);
      });
    }
    

    你可以这样使用它:

    fbPut("/foo/bar", "lol").then(res => {
      console.log("wrote data")
    })
    

    然后:

    fbGet("/foo/bar").then(data => {
      console.log(data); // prints "lol"
    }).catch(e => {
      console.log("error saving to firebase: ");
      console.log(e);
    })
    

    【讨论】:

    • 我想使用 REST API,这是最好的解决方案,但我在身份验证方面遇到了问题。我需要获得一个访问令牌,我发现很难找到关于此的好的文档。我已经关注了很多他们自己的文档,但还没有得到任何工作
    【解决方案5】:

    如果您使用基于节点的开发设置,另一种选择是使用来自herenode-lambda 包。本质上,它提供了用于设置、测试和部署到 lambda 的包装器。 node-lambda deploy 将打包您已安装的所有模块(例如使用 npm i --save firebase)并确保它们在 Lambda 本身上可用。我发现它对管理外部模块非常有帮助。

    【讨论】:

      【解决方案6】:

      对我来说,firebase-admin 应该可以解决问题。 https://firebase.google.com/docs/admin/setup

      感谢 Josiah Choi 建议 context.callbackWaitsForEmptyEventLoop。所以 lambda 不需要每次都初始化 Firebase。我的第一次跑步真的很慢。

        var firebase = require('firebase-admin');
        module.exports.Test = (event, context, callback) => {
      
        context.callbackWaitsForEmptyEventLoop = false;  //<---Important
      
        if(firebase.apps.length == 0) {   // <---Important!!! In lambda, it will cause double initialization.
          firebase.initializeApp({
            credential: firebase.credential.cert("serviceAccount.json"),
            databaseURL: <YOUR FIREBASE URL>
          });
      
        }
      
      
       firebase.database().ref('conversation').once('value').then(function(snapshot) {
          console.log (snapshot.val()) ;
         var bodyReturn = {
           input: snapshot.val()
         } ;
      
         callback(null,bodyReturn);
         context.succeed() ;
      });
      
      };
      

      【讨论】:

        【解决方案7】:

        在尝试了一些事情之后,这似乎对我有用(v 3.10.8):

        for(var i=0;i<5;i++)
        {
        
            var firebase = require('firebase');
            var config = {
                apiKey: "",
                authDomain: "",
                databaseURL: "",
                storageBucket: "",
                messagingSenderId: ""
              };
                if(firebase.apps)
                if(firebase.apps.length==0)
              firebase.initializeApp(config)
        
                firebase.database().ref().child("test").once('value').
                  then(function(snapshot) {
                    console.log(snapshot.val());
        
                                         });
        
          }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-21
          • 1970-01-01
          • 2016-11-26
          • 2012-12-08
          • 2017-11-29
          相关资源
          最近更新 更多