获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

配置您的环境

通常,您需要对函数进行额外配置,例如第三方 API 密钥或可调设置。 Firebase SDK for Cloud Functions 提供了内置的环境配置,让您可以轻松地为您的项目存储和检索此类数据。

您可以在三个选项之间进行选择:

  • 参数化配置(推荐用于大多数场景)。这提供了具有在部署时验证的参数的强类型环境配置,从而防止错误并简化调试。
  • 基于文件的环境变量配置。使用这种方法,您可以手动创建一个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文件,添加所需的变量,然后部署:

  1. 在您的functions/目录中创建一个.env文件:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. 打开.env文件进行编辑,然后添加所需的密钥。例如:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. 部署函数并验证是否已加载环境变量:

    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
PLANET=地球

观众=人类

观众=开发人类观众=刺激人类

给定这些单独文件中的值,与您的函数一起部署的一组环境变量将根据您的目标项目而有所不同:

$ 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_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICE
  • K_REVISION
  • 港口
  • K_CONFIGURATION

存储和访问敏感的配置信息

存储在.env文件中的环境变量可用于功能配置,但不应将它们视为存储敏感信息(如数据库凭据或 API 密钥)的安全方式。如果您将.env文件签入源代码管理,这一点尤其重要。

为了帮助您存储敏感配置信息,Cloud Functions for Firebase 与 Google Cloud Secret Manager集成。此加密服务安全地存储配置值,同时仍允许在需要时从您的函数轻松访问。

创建和使用密钥

要创建密钥,请使用 Firebase CLI。

要创建和使用密钥:

  1. 从本地项目目录的根目录运行以下命令:

    firebase functions:secrets:set SECRET_NAME

  2. 输入SECRET_NAME的值。

    CLI 回显成功消息并警告您必须部署函数才能使更改生效。

  3. 在部署之前,请确保您的函数代码允许函数使用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
      });
  4. 部署云功能:

    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

对于accessdestroy命令,您可以提供可选的 version 参数来管理特定版本。例如:

functions:secrets:access SECRET_NAME[@VERSION]

有关这些操作的更多信息,请通过-h命令查看 CLI 帮助。

秘密是如何计费的

Secret Manager 允许免费使用 6 个活动密钥版本。这意味着您每月可以在 Firebase 项目中免费拥有 6 个机密。

默认情况下,Firebase CLI 会尝试在适当的情况下自动销毁未使用的密钥版本,例如当您使用新版本的密钥部署函数时。此外,您可以使用functions:secrets:destroyfunctions: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
PLANET=地球

观众=人类

观众=开发人类观众=当地人

在本地上下文中启动时,模拟器会加载环境变量,如下所示:

  $ 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文件(在下面的示例中为localdevprod )中列出的每个别名或项目的配置输出为.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

请注意,在某些情况下,系统会提示您输入前缀以重命名导出的环境变量键。这是因为并非所有配置都可以自动转换,因为它们可能无效或可能是保留的环境变量 key

我们建议您在部署函数或将.env文件检入源代码控制之前仔细检查生成的.env文件的内容。如果任何值是敏感的并且不应泄露,请将它们从您的.env文件中删除,并将它们安全地存储在Secret Manager中。

您还需要更新函数代码。任何使用functions.config的函数现在都需要使用process.env ,如环境变量所示。

环境配置

firebase-functions v3.18.0发布环境变量支持之前,推荐使用functions.config()进行环境配置。这种方法仍然受支持,但我们建议所有新项目改为使用环境变量,因为它们更易于使用并提高代码的可移植性。

使用 CLI 设置环境配置

要存储环境数据,您可以使用Firebase CLI中的firebase functions:config:set命令。可以使用句点对每个键进行命名空间,以将相关配置组合在一起。请记住, keys 中只接受小写字符;不允许使用大写字符。

例如,要存储“某些服务”的客户端 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);