通常您需要为您的功能进行额外的配置,例如第三方 API 密钥或可调整的设置。适用于 Cloud Functions 的 Firebase SDK 提供内置环境配置,可以轻松为您的项目存储和检索此类数据。
您可以在三个选项中进行选择:
- 参数化配置(推荐用于大多数场景)。这提供了带有在部署时验证的参数的强类型环境配置,从而防止错误并简化调试。
- 基于文件的环境变量配置。使用这种方法,您可以手动创建一个dotenv文件来加载环境变量。
- 使用 Firebase CLI 和
functions.config
进行运行时环境配置。
对于大多数用例,建议使用参数化配置。这种方法使配置值在运行时和部署时都可用,除非所有参数都具有有效值,否则部署将被阻止。相反,带有环境变量的配置在部署时不可用。
参数化配置
Cloud Functions for Firebase 提供了一个接口,用于在您的代码库中以声明方式定义配置参数。这些参数的值在函数部署期间、设置部署和运行时选项时以及执行期间均可用。这意味着 CLI 将阻止部署,除非所有参数都具有有效值。
要在代码中定义参数,请遵循以下模型:
const functions = require('firebase-functions');
const { defineInt, defineString } = require('firebase-functions/params');
// Define some parameters
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
const welcomeMessage = defineString('WELCOME_MESSAGE');
// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
(req, res) => {
res.send(`${welcomeMessage.value()}! I am a function.`);
}
);
使用参数化配置变量部署函数时,Firebase CLI 首先尝试从本地 .env 文件加载它们的值。如果它们不存在于这些文件中并且没有default
,CLI 将在部署期间提示输入值,然后自动将它们的值保存到您的functions/
目录中名为.env.<project_ID>
的.env
文件中:
$ firebase deploy
i functions: preparing codebase default for deployment
? Enter a string value for ENVIRONMENT: prod
i functions: Writing new parameter values to disk: .env.projectId
…
$ firebase deploy
i functions: Loaded environment variables from .env.projectId
根据您的开发工作流程,将生成的.env.<project_ID>
文件添加到版本控制中可能会有用。
配置 CLI 行为
可以使用Options
对象配置参数,该对象控制 CLI 如何提示输入值。以下示例设置选项以验证电话号码的格式,提供简单的选择选项,并从 Firebase 项目自动填充选择选项:
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE', {default: 'Hello World',
description: 'The greeting that is returned to the caller of this function'});
const onlyPhoneNumbers = defineString('PHONE_NUMBER', {input: {text:
{validationRegex: /\d{3}-\d{3}-\d{4}/, validationErrorMessage: "Please enter
a phone number in the format XXX-YYY-ZZZZ"}}});
const selectedOption = defineString('PARITY', {input: {select: {options:
[{value: "odd"}, {value: "even"}]}}})
const storageBucket = defineString('BUCKET', {input: {resource: {type:
"storage.googleapis.com/Bucket"}}, description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets"})
参数类型
参数化配置为参数值提供强类型,还支持来自 Cloud Secret Manager 的秘密。支持的类型有:
- 秘密
- 细绳
- 布尔值
- 整数
- 漂浮
参数值和表达式
Firebase 会在部署时和函数执行时评估您的参数。由于这些双重环境,在比较参数值以及使用它们为函数设置运行时选项时必须格外小心。
要将参数作为运行时选项传递给您的函数,请直接传递它:
const functions = require('firebase-functions');
const { defineInt} = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO\_WORLD\_MININSTANCES');
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
(req, res) => {
//…
此外,如果您需要与参数进行比较以了解选择哪个选项,则需要使用内置比较器而不是检查值:
const functions = require('firebase-functions');
const { defineBool } = require('firebase-functions/params');
const environment = params.defineString(‘ENVIRONMENT’, {default: ‘dev’});
// use built-in comparators
const minInstancesConfig =environment.equals('PRODUCTION').thenElse(10, 1);
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
(req, res) => {
//…
仅在运行时使用的参数和参数表达式可以通过它们的value
函数访问:
const functions = require('firebase-functions');
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE');
// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.https.onRequest(
(req, res) => {
res.send(`${welcomeMessage.value()}! I am a function.`);
}
);
内置参数
Cloud Functions SDK 提供三个预定义参数,可从firebase-functions/params
子包中获取:
-
projectId
— 运行函数的 Cloud 项目。 -
databaseUrl
— 与函数关联的实时数据库实例的 URL(如果在 Firebase 项目上启用)。 -
storageBucket
— 与函数关联的 Cloud Storage 存储桶(如果在 Firebase 项目上启用)。
这些功能在所有方面都类似于用户定义的字符串参数,除了因为它们的值始终为 Firebase CLI 所知,它们的值永远不会在部署时被提示,也不会保存到.env
文件中。
秘密参数
使用defineSecret()
定义的Secret
类型的参数表示具有存储在 Cloud Secret Manager 中的值的字符串参数。与检查本地.env
文件并在丢失时向文件写入新值不同,秘密参数检查 Cloud Secret Manager 中是否存在,并在部署期间以交互方式提示输入新秘密的值。
以这种方式定义的秘密参数必须绑定到应该访问它们的各个函数:
const functions = require('firebase-functions');
const { defineSecret } = require('firebase-functions/params');
const discordApiKey = defineSecret('DISCORD_API_KEY');
export const postToDiscord = functions.runWith({ secrets: [discordApiKey] }).https.onRequest(
(req, res) => {
const apiKey = discordApiKey.value();
//…
因为秘密的值在函数执行之前是隐藏的,所以您不能在配置函数时使用它们。
环境变量
Cloud Functions for Firebase 支持dotenv文件格式,用于将.env
文件中指定的环境变量加载到您的应用程序运行时。部署后,可以通过process.env
接口读取环境变量。
要以这种方式配置您的环境,请在您的项目中创建一个.env
文件,添加所需的变量,然后部署:
在您的
functions/
目录中创建一个.env
文件:# Directory layout: # my-project/ # firebase.json # functions/ # .env # package.json # index.js
打开
.env
文件进行编辑,并添加所需的密钥。例如:PLANET=Earth AUDIENCE=Humans
部署函数并验证是否加载了环境变量:
firebase deploy --only functions # ... # i functions: Loaded environment variables from .env. # ...
部署自定义环境变量后,您的函数代码可以使用process.env
语法访问它们:
// Responds with "Hello Earth and Humans"
exports.hello = functions.https.onRequest((request, response) => {
response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});
部署多组环境变量
如果您的 Firebase 项目需要一组替代环境变量(例如暂存与生产),请创建一个.env. <project or alias >
文件并在其中写入项目特定的环境变量。来自.env
和项目特定.env
文件(如果存在)的环境变量将包含在所有已部署的函数中。
例如,一个项目可能包括这三个文件,其中包含用于开发和生产的略有不同的值:
.env | .env.dev | .env.prod |
行星=地球 观众=人类 | 观众=开发人员 | 观众=生产人类 |
鉴于这些单独文件中的值,与您的函数一起部署的环境变量集将根据您的目标项目而有所不同:
$ firebase use dev
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.dev.
# Deploys functions with following user-defined environment variables:
# PLANET=Earth
# AUDIENCE=Dev Humans
$ firebase use prod
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.prod.
# Deploys functions with following user-defined environment variables:
# PLANET=Earth
# AUDIENCE=Prod Humans
保留的环境变量
一些环境变量键保留供内部使用。不要在.env
文件中使用这些键中的任何一个:
- 所有以 X_GOOGLE_ 开头的键
- 所有以 EXT_ 开头的键
- 所有以 FIREBASE_ 开头的键
- 以下列表中的任意键:
- CLOUD_RUNTIME_CONFIG
- 入口点
- GCP_PROJECT
- GCLOUD_PROJECT
- GOOGLE_CLOUD_PROJECT
- FUNCTION_TRIGGER_TYPE
- FUNCTION_NAME
- FUNCTION_MEMORY_MB
- FUNCTION_TIMEOUT_SEC
- FUNCTION_IDENTITY
- 功能区域
- FUNCTION_TARGET
- FUNCTION_SIGNATURE_TYPE
- K_服务
- K_修订版
- 港口
- K_配置
存储和访问敏感的配置信息
存储在.env
文件中的环境变量可用于功能配置,但您不应将它们视为存储敏感信息(如数据库凭据或 API 密钥)的安全方式。如果您将.env
文件签入源代码管理,这一点尤其重要。
为了帮助您存储敏感的配置信息,Cloud Functions for Firebase 与 Google Cloud Secret Manager集成。此加密服务安全地存储配置值,同时仍允许在需要时从您的函数轻松访问。
创建和使用秘密
要创建机密,请使用 Firebase CLI。
创建和使用秘密:
从本地项目目录的根目录运行以下命令:
firebase functions:secrets:set SECRET_NAME
输入SECRET_NAME的值。
CLI 回显一条成功消息并警告您必须部署函数才能使更改生效。
在部署之前,请确保您的函数代码允许函数使用
runWith
参数访问机密:exports.processPayment = functions // Make the secret available to this function .runWith({ secrets: ["SECRET_NAME"] }) .onCall((data, context) => { const myBillingService = initializeBillingService( // reference the secret value process.env.SECRET_NAME ); // Process the payment });
部署云功能:
firebase deploy --only functions
现在您将能够像访问任何其他环境变量一样访问它。相反,如果另一个未在runWith
中指定秘密的函数尝试访问该秘密,它会收到一个未定义的值:
exports.anotherEndpoint = functions.https.onRequest((request, response) => {
response.send(`The secret API key is ${process.env.SECRET_NAME}`);
// responds with "The secret API key is undefined" because the `runWith` parameter is missing
});
部署您的函数后,它将可以访问秘密值。只有在其runWith
参数中明确包含秘密的函数才能访问该秘密作为环境变量。这有助于您确保秘密值仅在需要时可用,从而降低意外泄露秘密的风险。
管理秘密
使用 Firebase CLI 管理您的机密。在以这种方式管理机密时,请记住,某些 CLI 更改需要您修改和/或重新部署相关功能。具体来说:
- 每当您为秘密设置新值时,您必须重新部署所有引用该秘密的函数,以便它们获取最新值。
- 如果您删除一个秘密,请确保您部署的所有函数都没有引用该秘密。使用已删除的秘密值的函数将静默失败。
以下是用于机密管理的 Firebase CLI 命令的摘要:
# Change the value of an existing secret firebase functions:secrets:set SECRET_NAME # View the value of a secret functions:secrets:access SECRET_NAME # Destroy a secret functions:secrets:destroy SECRET_NAME # View all secret versions and their state functions:secrets:get SECRET_NAME # Automatically clean up all secrets that aren't referenced by any of your functions functions:secrets:prune
对于access
和destroy
命令,您可以提供可选的版本参数来管理特定版本。例如:
functions:secrets:access SECRET_NAME[@VERSION]
有关这些操作的更多信息,请将-h
与命令一起传递以查看 CLI 帮助。
密文如何计费
Secret Manager 允许 6 个免费的活动密钥版本。这意味着您每月可以在 Firebase 项目中免费获得 6 个密文。
默认情况下,Firebase CLI 会尝试在适当的时候自动销毁未使用的密钥版本,例如当您使用新版本的密钥部署函数时。此外,您可以使用functions:secrets:destroy
和functions:secrets:prune
主动清理未使用的秘密。
Secret Manager 允许每月对一个密钥进行 10,000 次未计费的访问操作。每次冷启动时,函数实例只读取其runWith
参数中指定的秘密。如果您有大量读取大量机密的函数实例,您的项目可能会超出此限额,届时您将被收取每 10,000 次访问操作 0.03 美元的费用。
有关详细信息,请参阅Secret Manager 定价。
仿真器支持
使用 dotenv 的环境配置旨在与本地Cloud Functions 模拟器进行互操作。
使用本地 Cloud Functions 模拟器时,您可以通过设置.env.local
文件来覆盖项目的环境变量。 .env.local
的内容优先于.env
和项目特定的.env
文件。
例如,一个项目可能包括这三个文件,其中包含用于开发和本地测试的略有不同的值:
.env | .env.dev | .env.local |
行星=地球 观众=人类 | 观众=开发人员 | 观众=当地人 |
在本地上下文中启动时,模拟器加载环境变量,如下所示:
$ firebase emulators:start
i emulators: Starting emulators: functions
# Starts emulator with following environment variables:
# PLANET=Earth
# AUDIENCE=Local Humans
Cloud Functions 模拟器中的机密和凭据
Cloud Functions 模拟器支持使用机密来存储和访问敏感的配置信息。默认情况下,模拟器将尝试使用应用程序默认凭据访问您的生产机密。在 CI 环境等特定情况下,由于权限限制,模拟器可能无法访问秘密值。
类似于 Cloud Functions 模拟器对环境变量的支持,您可以通过设置.secret.local
文件来覆盖机密值。这使您可以轻松地在本地测试您的函数,尤其是在您无权访问秘密值的情况下。
从环境配置迁移
如果您一直在使用带有functions.config
的环境配置,则可以将现有配置迁移为环境变量( dotenv格式)。 Firebase CLI 提供了一个导出命令,该命令将目录的.firebaserc
文件中列出的每个别名或项目的配置(在下面的示例中为local
、 dev
和prod
)输出为.env
文件。
要迁移,请使用firebase functions:config:export
命令导出现有环境配置:
firebase functions:config:export i Importing configs from projects: [project-0, project-1] ⚠ The following configs keys could not be exported as environment variables: ⚠ project-0 (dev): 1foo.a => 1FOO\_A (Key 1FOO\_A must start with an uppercase ASCII letter or underscore, and then consist of uppercase ASCII letters, digits, and underscores.) Enter a PREFIX to rename invalid environment variable keys: CONFIG\_ ✔ Wrote functions/.env.prod ✔ Wrote functions/.env.dev ✔ Wrote functions/.env.local ✔ Wrote functions/.env
请注意,在某些情况下,系统会提示您输入前缀以重命名导出的环境变量键。这是因为并非所有配置都可以自动转换,因为它们可能无效或可能是保留的环境变量键。
我们建议您在部署函数或将.env
文件签入源代码管理之前仔细查看生成的.env
文件的内容。如果任何值是敏感的并且不应泄露,请将它们从您的.env
文件中删除并将它们安全地存储在Secret Manager中。
您还需要更新函数代码。任何使用functions.config
的函数现在都需要使用process.env
,如环境变量所示。
环境配置
在firebase-functions v3.18.0
发布环境变量支持之前,推荐使用functions.config()
进行环境配置。这种方法仍然受支持,但我们建议所有新项目改用环境变量,因为它们更易于使用并提高代码的可移植性。
使用 CLI 设置环境配置
要存储环境数据,您可以在Firebase CLI中使用firebase functions:config:set
命令。每个键都可以使用句点命名空间,将相关配置组合在一起。请记住,键中只接受小写字符;不允许使用大写字符。
例如,要存储“某些服务”的客户端 ID 和 API 密钥,您可以运行:
firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"
检索当前环境配置
要检查项目的环境配置中当前存储的内容,您可以使用firebase functions:config:get
。它会输出类似这样的 JSON:
{
"someservice": {
"key":"THE API KEY",
"id":"THE CLIENT ID"
}
}
此功能基于Google Cloud Runtime Configuration API 。
使用functions.config
访问函数中的环境配置
在保留的firebase
命名空间下自动提供一些配置。通过functions.config()
在运行的函数中提供环境配置。要使用上面的配置,您的代码可能如下所示:
const functions = require('firebase-functions');
const request = require('request-promise');
exports.userCreated = functions.database.ref('/users/{id}').onWrite(event => {
let email = event.data.child('email').val();
return request({
url: 'https://someservice.com/api/some/call',
headers: {
'X-Client-ID': functions.config().someservice.id,
'Authorization': `Bearer ${functions.config().someservice.key}`
},
body: {email: email}
});
});
使用环境配置来初始化模块
某些 Node 模块无需任何配置即可准备就绪。其他模块需要额外配置才能正确初始化。我们建议您将此配置存储在环境配置变量中,而不是对其进行硬编码。这可以帮助您保持代码的可移植性,让您可以开源应用程序或轻松地在生产版本和暂存版本之间切换。
例如,要使用Slack Node SDK模块,您可以这样写:
const functions = require('firebase-functions');
const IncomingWebhook = require('@slack/client').IncomingWebhook;
const webhook = new IncomingWebhook(functions.config().slack.url);
在部署之前,设置slack.url
环境配置变量:
firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX
其他环境命令
firebase functions:config:unset key1 key2
从配置中删除指定的键firebase functions:config:clone --from <fromProject>
将另一个项目的环境克隆到当前活动的项目中。
自动填充的环境变量
有一些环境变量会自动填充到函数运行时和本地模拟函数中。其中包括由 Google Cloud 填充的那些,以及特定于 Firebase 的环境变量:
process.env.FIREBASE_CONFIG
:提供以下 Firebase 项目配置信息:
{
databaseURL: 'https://databaseName.firebaseio.com',
storageBucket: 'projectId.appspot.com',
projectId: 'projectId'
}
当您不带参数初始化 Firebase Admin SDK 时,会自动应用此配置。如果您正在用 JavaScript 编写函数,请像这样初始化:
const admin = require('firebase-admin');
admin.initializeApp();
如果您在 TypeScript 中编写函数,请像这样初始化:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import 'firebase-functions';
admin.initializeApp();
如果您需要使用服务帐户凭据使用默认项目配置初始化 Admin SDK,您可以从文件加载凭据并将它们添加到FIREBASE_CONFIG
,如下所示:
serviceAccount = require('./serviceAccount.json');
const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);