声明单独的 Firebase Cloud Functions 并仍然使用 Express.js
Posted
技术标签:
【中文标题】声明单独的 Firebase Cloud Functions 并仍然使用 Express.js【英文标题】:Declare separate Firebase Cloud Functions and still use Express.js 【发布时间】:2019-06-27 17:51:15 【问题描述】:有many examples 使用 Express for Firebase Cloud Functions。
在我发现的每个示例中,代码都将 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 控制台中,我有我的 hello 函数以及我的 index.js 中的另一个函数:
这也意味着 Firebase 将为每个函数创建不同的节点/实例:hello
和 emphemeralKey
。
我会在 Firebase 控制台中为每个函数单独记录日志。
我想使用中间件来确保将有效的身份验证令牌传递给我的端点云函数,例如 Firebase example,但我不想使用单个“应用程序”单个云函数,我更喜欢专用函数用于我的 index.js 中的函数导出。
【问题讨论】:
为什么这对你很重要?有什么要求? @DougStevenson 我在我的问题中解释了 Firebase Cloud Functions 如何为每个实例部署一个节点以及如何处理日志记录。此外,我现在和将来的要求不会验证或否定我的问题。 我并不是要使您的问题无效。我试图了解真正的问题在这里。所以你想要的只是为每个端点单独记录?我不知道“部署一个节点实例”是什么意思。我想你可能不明白 Cloud Functions 是如何扩展的。 不,我不只是想要单独的日志记录,我想要为每个公开的函数创建单独的云函数节点/实例,否则我有一个“应用程序”节点和应用程序中的所有请求端点。跨度> 当前部署有什么问题?单个函数将扩展到 1000 个实例。 【参考方案1】:有趣的讨论。
我选择相同的方法:一个“端点”(也称为“/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;
我的“你好”端点:
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);
似乎对我们很有效:)
【讨论】:
【参考方案2】:感谢 Doug Stevenson 的回答和帮助。不过我想提供我自己的答案。
所以一般来说,我的问题的答案是:不,你不能。
正如 Doug 所指出的,这对于许多人的扩展需求来说不是问题。 Firebase 将创建多达 1,000 个函数实例以进行扩展。
我想提供一个与 Doug 略有不同的答案,即我将如何编写 Express 应用程序并为项目提供不同的 Firebase 云功能:
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 路由,例如:
/payment/someaction (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
【讨论】:
@DougStevenson 你觉得上述方法有什么问题吗? 我来这里是为了回答这个问题,得出的结论与你对这个答案的结论相同。我还看到了拆分它们的另一个正当理由,那就是您可以更轻松地从控制台和 API 级别查看错误、性能、延迟和内存等。当所有 API 都捆绑在同一个函数下时,很难确定 1 是否为异常值。 @DougStevenson 对吗?还是有其他解决方法 @Philberg 同意,我使用这种方法的另一个好处是拥有用于信用卡支付处理的测试 API 和实时 API @Philberg 我刚刚添加了一个示例,说明能够使用此方法进行测试和生产 API 的好处,请参阅我的答案的更新 使用 express 执行此操作的唯一方法是从字面上导出一个单独的 express 实例来执行此操作,这似乎很愚蠢。哦,好吧,希望 GCF 尽快改进【参考方案3】:如果您只有一个 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,这将帮助您更好地组织和监控您的函数生成的不同类型的日志。
【讨论】:
对了,我也可以创建多个快递应用对吗? const app1 = express() 和 const app2 = express() 是吗? 当然,如果这对您的情况有所帮助。如果您要为每个应用程序提供一个路由,则不妨使用常规的旧 HTTP 函数。您仍然可以将 cors 中间件应用于常规 HTTP 函数。 github.com/firebase/functions-samples/blob/Node-8/quickstarts/… 感谢您的帮助,我没有意识到我最近一直在观看您的一些 Firebase 视频,我以为您看起来很眼熟 :)以上是关于声明单独的 Firebase Cloud Functions 并仍然使用 Express.js的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 中的 cloud_firestore 和 firebase_auth 兼容性问题
如何在 Firebase Cloud Functions 中模拟辅助函数?
具有 Cloud Functions for Firebase 的自定义观察者
Firebase Cloud Messaging 推送通知在 Android 上不能在前台工作,只能在后台工作