因此,您想同时使用Google的functions-framework?
您可能以前已经在Firebase中编写了云功能,在该firebase中,Firebase Local Emulator Suite允许您使用单个命令(firebase emulators:start
)在单个本地服务器上同时运行所有功能。
该功能框架无法提供可以在此外进行此操作的模拟器。但是,您可以很容易地自己写一个,并且以这种方式近似Firebase的本地发展经验。
这种方法将您的功能仅用于开发目的。您仍然可以将功能分别部署到Google Cloud。
示例设置
在此示例中,我有以下目录结构:
├── package.json
└── src
├── index.js
└── functions
├── firstFunction.js
└── secondFunction.js
功能脚本
这两个函数本身都是全面的express.js处理程序,就像它们在firebase中一样。
要测试两个函数可以交互,第一个函数返回http 302重定向,将其重定向到第二个功能上的get请求。
// src/functions/firstFunction.js
export const firstFunction = async (req, res) => {
res.redirect('/secondFunction');
}
// src/functions/secondFunction.js
export const secondFunction = async (req, res) => {
res.send("OK! You were redirected here.");
}
package.json
package.json
将src/index.js
称为主要节点脚本。我们还需要告诉函数框架以定位index.js
模块中的index
导出:
// package.json
...
"type": "module",
// Tells the functions-framework where to look for exports.
"main": "src/index.js",
"scripts": {
"start": "functions-framework --target=index", // Select target export
"debug": "functions-framework --target=index --debug"
}
...
index.js
index.js
文件是此设置的核心。我们将在一个局部地址上公开所有功能,并单独公开功能。
// src/index.js
import express from "express"
import { firstFunction } from "./functions/firstFunction.js";
import { secondFunction } from "./functions/secondFunction.js";
// Solution to expose multiple cloud functions locally
const app = express();
app.use('/firstFunction', firstFunction);
app.use('/secondFunction', secondFunction);
export {app as index, firstFunction, secondFunction};
本地函数框架将针对从index.js
导出的index
导出,请参见上面的package.json
。 index
导出仅用于本地开发目的,因此我们可以在本地一次运行多个功能。
我们仍然导出各个功能,因此我们可以轻松地分别部署两个功能。请参阅以下单独部署功能。
一起运行功能
现在,如果我们运行npm run start
,则开发服务器将在http://localhost:8080
上启动。
运行curl http://localhost:8080/firstFunction
将打印OK! You were redirected here.
,证明两个功能都在同一时间运行。
如果您仍然想隔离测试功能,则可以运行functions-framework --target=firstFunction
,之后您可以使用curl http://localhost:8080
来调用它。
单独部署功能
函数仍然可以单独部署,使用gcloud
cli:
gcloud functions deploy firstFunction --project=my-project --runtime nodejs16 --trigger-http --allow-unauthenticated --security-level=secure-always --region=eyour-region --entry-point=firstFunction --memory=128MB --timeout=60s
gcloud functions deploy secondFunction --project=my-project --runtime nodejs16 --trigger-http --allow-unauthenticated --security-level=secure-always --region=your-region --entry-point=secondFunction --memory=128MB --timeout=60s
这里的关键是--entrypoint firstFunction
标志,它类似于functions-framework
命令上的--target
标志。它选择了索引脚本的模块导出,该导出应被视为云函数的入口点。
you 可以还将index
导出为一个将所有函数结合在一起的单个函数,但是您将在云上调用/index/firstFunction
和/index/secondFunction
,然后您可以t scale或t scale或单独修改函数运行时间。
警告:对req.path
和其他快速变量的影响
似乎使用Express``这种方式''不是一种适当的方式,可以同时模拟在Google Cloud中运行的多个单个函数。有一些警告。
req.path
3
如果您需要在应用程序中访问req.path
怎么办?这种行为与在Google Cloud中或本地运行单个功能的行为不同吗?
当您作为本地函数运行单个函数,然后在访问该功能中的req.path
时在http://localhost:8080/
上调用它时,它将产生/
。在https://your-google-cloud-domain/firstFunction
上调用在Google Cloud中运行的函数的功能也同样存在:访问req.path
仍然会产生/
,即使您称为实际的URL路径为/firstFunction
!
我们是否在本地开发环境中正确复制了这种行为?重要的是要在本地开发设置和生产设置之间达到均衡。
答案是是。请参阅req.path的快递文档:
从中间件调用时,安装点不包括在
req.path
中。
当我们致电app.use('/firstFunction', firstFunction);
时,我们将firstFunction
注册为application-level middleware1
省略点的省略意味着,如果我们运行导出的Express index
App(== app
),然后我们将http://localhost:8080/firstFunction
称为http://localhost:8080/firstFunction
,那么它似乎似乎 在其上运行的实际firstFunction
函数http://localhost:8080/
,而不是http://localhost:8080/firstFunction
。
req.originalUrl
â
这个属性很像
req.url
;但是,它保留了原始请求URL,使您可以自由地重写req.url
,以实现内部路由。例如,app.use()的安装功能将重写req.url
以剥离安装点。
req.originalUrl
不像在真实生产的Google Cloud多功能设置中那样行事。
在Google Cloud上,req.originalUrl
不包括函数名称。这可能是由于Google Cloud的一些外部路线。
使用上述索引。
确保您的代码不依赖于某些决策的值req.originalUrl
。如果是这样,您可能需要适应此代码。
更多的?
我可能没有其他警告,我对此设置不知道,但就目前而言,它适合我的目的,而当地的开发方便还值得以后的任何并发症。
参考
闭幕说明:此解决方案基于您在研究此问题时可能已经看到的an answer in a related GitHub Issue thread。
我写这篇文章是因为该线程包含了与我的用例(以及一些不必要的戏剧)相关的几种方法。我希望开发人员习惯了Firebase函数模型找到此设置建议很有帮助。