声明单独的Firebase云函数并仍使用Express.js

f45qwnt8  于 2022-11-17  发布在  其他
关注(0)|答案(4)|浏览(123)

many examples的使用Express的Firebase云函数。
在我发现的每个示例中,代码都将Express应用程序公开为单个云函数:

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 Console中,我有hello函数,还有index.js中的另一个函数:

这也意味着Firebase将为每个函数创建不同的节点/示例:helloemphemeralKey中的一个或多个。
我将在Firebase控制台中获得每个功能的单独日志记录。
我希望使用中间件来确保有效的身份验证令牌被传递到我的端点云函数,如Firebase example,但我不希望使用单个“应用程序”单个云函数,我更希望在我的index.js中使用专用函数进行函数导出。

u5i3ibmn

u5i3ibmn1#

感谢道格史蒂文森的回答和帮助。不过我想提供我自己的答案。
所以我的问题的答案是,一般来说:不,你不能。
正如Doug所指出的,这对于许多人的扩展需求来说不是问题,Firebase将创建多达1,000个要扩展的函数示例。
对于如何编写Express应用程序并为项目提供不同的Firebase云函数,我想提供与Doug略有不同的答案:

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)
  • /order(获取、放置、发布等)

另一个好处是,我可以为信用卡支付/处理之类的事情提供“测试”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 url:

/us-central1/apptest

/us-central1/app
nzkunb0c

nzkunb0c2#

有趣的讨论。
我选择了同样的方法:一个“端点”(也称为根路由,如“/posts”、“/users”)==一个专用的云函数(原因已经提到+它更像“µ服务”,对我来说是“lambda函数”)。
为了“干”,我所有的函数都导入了一个“express”生成器。我在一个地方配置了我的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;

我的“你好”端点:

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

/**
 * /hello
 */

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

module.exports = app;

My index.js(主导出):

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

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

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

似乎对我们很有效:)

kmb7vmvb

kmb7vmvb3#

如果您只有一个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)。但是,您并没有从本质上限制某些路由在不同的函数中被调用。这取决于您是否确保客户端正在使用您想要的函数。
如果你是出于性能原因而尝试进行这种拆分,我会考虑这种过早的优化。云功能将根据需要无缝地扩展你的应用,使其超出单个服务器示例。如果你希望超过documented limits,像这样拆分功能 * 可能 * 有助于可扩展性,但我认为这种情况并不常见。在不了解实际情况的情况下,观察到的性能特征,如果你的应用,这是不可能说的。如果你 * 是 * 超出限制,contact support,以帮助解释什么是没有发生在你的部署预期的方式。
如果您发现云函数的基本日志记录在监控每个路由时没有帮助,您应该查看自定义StackDriver日志记录,这将帮助您更好地组织和监控函数生成的不同类型的日志。

7z5jn7bk

7z5jn7bk4#

我只是觉得注册这个很有用,因为它对我很有用...如果你觉得有用,你可以做这样的事情:

const app = express();

export const appGetUser = functions.https.onRequest(
  app.get("/users/:userId", getUser)
);

这样,它就成为一个Express应用程序的整体,但每个API端点将被视为一个单独的Firebase云函数。您需要通过https://.../myFirebaseProject/us-central1/appGetUser/users/{userId}之类的方式访问它们。
然后,如果您希望有一个冗余较少的端点:

export const users = functions.https.onRequest(
  app.get("/:userId", getUser)
);

现在是https://.../myFirebaseProject/us-central1/users/{userId}

相关问题