声明单独的Firebase Cloud Functions并仍使用Express.js

时间:2019-02-03 23:11:14

标签: node.js firebase express firebase-authentication google-cloud-functions

many examples中有将Express用于Firebase云功能的

在我发现的每个示例中,代码都将Express应用程序公开为单个Cloud Function:

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

对于一个人的Firebase项目功能,这意味着他们将看到一个名为“ app”的条目,并且所有Express.js HTTP侦听器的所有日志都将转到Firebase中的一个位置。这也意味着,无论Express.js应用程序有多大,Firebase都会在生产环境中为该应用程序部署一个功能。

或者,当使用firebase-functions.https.onRequest时,对于每种导出,例如在Typescript中,您将获得单独的功能:

export const hello = functions.https.onRequest(async (req, res) => {
  res.status(200).send('hello world');
});

在Firebase控制台中,我有我的hello函数以及index.js中的另一个函数:

enter image description here

这还意味着Firebase将为每个功能helloemphemeralKey创建不同的节点/实例。

在Firebase控制台中,我将为每个功能分别记录日志。

我想使用中间件来确保将有效的身份验证令牌传递给Firebase example这样的端点云功能,但是我不希望不使用单个“应用程序”单个云功能,而希望使用在index.js中用于函数导出的专用函数。

3 个答案:

答案 0 :(得分:1)

感谢Doug Stevenson的回答和帮助。我想提供自己的答案。

所以我的问题的答案通常是:不,你不能。

正如道格指出的那样,对于许多人的扩展需求而言,这不是问题。 Firebase最多可以创建1000个函数实例以进行扩展。

我想提供与道格稍有不同的答案,说明我将如何编写Express应用并为项目提供不同的Firebase Cloud功能:

const payment = express()
const order = express()
payment.get('/route', ...)
order.get('/route', ...)
export const payment = functions.https.onRequest(payment)
export const order = functions.https.onRequest(order)

这里的优点是我可以开始表达REST或RPC路由,例如:

  • /付款/某些行为(RPC)
  • /订单(获取,放置,发布等)

另一个好处是,我可以为信用卡付款/处理之类的事情提供“测试” API和“实时” API:

// [START Express LIVE App]


// [START get user]
app.get('/user', async (req, res) => {
  await handleGetUser(req, res, paymentServiceLive);
});
// [END get user]

// [START claim]
app.post('/claim', async (req, res) => {
  await handleClaim(req, res, claimEmailTo);
});
// [END claim]

// [START user]
app.post('/user', async (req, res) => {
  await handleUserPost(req, res, paymentServiceLive);
});
// [END user]

// [START ephemeralKey]
app.post('/ephemeralKey', async (req, res) => {
  await handleEphemeralKey(req, res, paymentServiceLive);
});
// [END ephemeralKey]


// [START charge]
app.post('/charge', async (req, res) => {
  await handleCharge(req, res, paymentServiceLive);
});
// [END charge]

// [START purchase]
app.post('/purchase', async (req, res) => {
  await handlePurchase(req, res, paymentServiceLive);
});
// [END purchase]

//Expose Express API as a single Cloud Function:
exports.app = functions.https.onRequest(app);

// [END Express LIVE App]



// [START Express TEST App]

// [START get user]
appTest.get('/user', async (req, res) => {
  console.log('appTest /user get', req);
  await handleGetUser(req, res, paymentServiceTest);
});
// [END get user]

// [START claim]
appTest.post('/claim', async (req, res) => {
  await handleClaim(req, res, claimEmailToTest, true);
});
// [END claim]


// [START user]
appTest.post('/user', async (req, res) => {
  console.log('appTest /user post', req);
  await handleUserPost(req, res, paymentServiceTest);
});
// [END user]

// [START ephemeralKey]
appTest.post('/ephemeralKey', async (req, res) => {
  await handleEphemeralKey(req, res, paymentServiceTest)
});
// [END ephemeralKey]


// [START charge]
appTest.post('/charge', async (req, res) => {
  await handleCharge(req, res, stripeTest);
});
// [END charge]

// [START purchase]
appTest.post('/purchase', async (req, res) => {
  await handlePurchase(req, res, paymentServiceTest);
});
// [END purchase]

//Expose Express API as a single Cloud Function:np
exports.apptest = functions.https.onRequest(appTest);

// [END Express TEST App]

这使我拥有一个开发环境和一个实时环境。在我的应用程序配置文件中,我只有一个不同的API网址:

/us-central1/apptest

/us-central1/app

答案 1 :(得分:0)

如果只有一个Express应用程序,则无法在项目中的不同逻辑功能之间划分其路由。如果您必须尝试在多个功能之间分配负载,则可以将同一Express应用程序部署到所需的单个功能中。

const app = express()
app.get('/route1', ...)
app.get('/route2', ...)
export const f1 = functions.https.onRequest(app)
export const f2 = functions.https.onRequest(app)
// etc

现在,您可以尝试解决不同功能(及其产生的不同URL)之间的不同路由。但是您并没有固有地限制某些路由不能在不同的函数中调用。确保您的客户端正在使用您想要的功能由您决定。

如果出于性能原因尝试执行此拆分,我会考虑进行这种过早的优化。 Cloud Functions将根据需要无缝扩展您的应用程序,而不仅仅是单个服务器实例。如果您希望超过documented limits,那么像这样 这样的功能拆分可能会有助于扩展性,但是我希望这并不常见。如果不了解您的应用程序的实际,观察到的性能特征,就很难说。如果您 超出限制,请contact support来帮助您解释部署中未发生的事情。

如果在监视每个路由时发现Cloud Functions的基本日志无用,则应查看custom StackDriver logging,这将有助于您更好地组织和监视功能的不同类型的日志生成。

答案 2 :(得分:0)

有趣的讨论。

我选择相同的方法:一个“端点”(又称根路由,如“ / posts”,“ / users”)==专用的云功能(由于已经被唤起的原因,而更多的是“ µservice like”,它是对我来说,什么是“ lambda函数”。

要“干燥”我的所有功能,请导入“表达”生成器。我将Express实例配置在一处。

const express = () => {
  const express = require("express");
  const cors = require("cors")({ origin: true });
  const morgan = require("morgan");
  const helmet = require("helmet");

  const app = express();

  app.use(helmet());
  app.use(helmet.noCache());
  app.use(cors);
  app.use(morgan("combined"));

  return app;
};

module.exports = express;

我的“ hello”端点:

const app = require("./../../express")();

/**
 * /hello
 */

app.get("/", (req, res) => {
  return res.send("Hello World");
});

module.exports = app;

我的index.js(主要导出):

const helloApi = require("./api/hello");

const https = functions.region("europe-west1").https;

module.exports.hello = https.onRequest(helloApi);

似乎对我们来说很好:)