配置您的环境

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

您可以使用 Firebase CLI 和 functions.config 选择基于文件的环境变量配置(推荐)或运行时环境配置。本指南对这两种方法进行了介绍。

环境变量

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=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

鉴于这些单独文件中的值,随函数部署的环境变量集会因目标项目而异:

$ 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
  • ENTRY_POINT
  • 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
  • PORT
  • K_CONFIGURATION

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

存储在 .env 文件中的环境变量可用于函数配置,但您不应认为它们是存储数据库凭据或 API 密钥等敏感信息的安全方式。如果您将 .env 文件签入源代码控制系统,这一点尤为重要。

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

创建和使用 Secret

如需创建 Secret,请使用 Firebase CLI。

如需创建和使用 Secret,请执行以下操作

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

    firebase functions:secrets:set SECRET_NAME

  2. 输入 SECRET_NAME 的值。

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

  3. 在部署之前,请确保您的函数代码允许函数使用 runWith 参数访问 Secret:

    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. 部署 Cloud Functions 函数:

    firebase deploy --only functions

现在,您可以像访问任何其他环境变量一样对其进行访问。 相对地,如果另一个没有在 runWith 中指定 Secret 的函数试图访问该 Secret,则会收到一个未定义的值:

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
});

函数部署后便可访问 Secret 值。只有在其 runWith 参数中明确包含 Secret 的函数才能以环境变量的形式访问该 Secret。这有助于确保 Secret 值仅在需要时才可用,从而降低意外泄露 Secret 的风险。

管理 Secret

使用 Firebase CLI 管理您的 Secret。以这种方式管理 Secret 时,请记住,某些 CLI 更改需要您修改和/或重新部署关联的函数。具体而言:

  • 每次为 Secret 设置新值时,您都必须重新部署所有引用该 Secret 的函数,以使它们获取最新值。
  • 如果您删除 Secret,请确保已部署的所有函数均未引用该 Secret。使用已删除的 Secret 值的函数将静默失败。

下面总结了用于 Secret 管理的 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 命令,您可以提供可选的版本参数来管理特定版本。例如:

functions:secrets:access SECRET_NAME[@VERSION]

如需详细了解这些操作,请使用命令传递 -h 以查看 CLI 帮助。

Secret 的结算方式

Secret Manager 允许您免费拥有 6 个有效的 Secret 版本。这意味着一个 Firebase 项目每月可以免费拥有 6 个 Secret。

默认情况下,Firebase CLI 会在适当的时候(例如,在使用新版本的 Secret 部署函数时)尝试自动销毁未使用的 Secret 版本。此外,您还可以使用 functions:secrets:destroyfunctions:secrets:prune 主动清理未使用的 Secret。

Secret Manager 允许每月对一个 Secret 执行 10,000 次未结算的访问操作。函数实例会在每次冷启动时仅读取在其 runWith 参数中指定的 Secret。如果您有许多函数实例读取大量 Secret,则您的项目可能会超出此限额,此时系统会按照每 10,000 次访问操作 $0.03 的费率向您收取费用。

如需了解详情,请参阅 Secret Manager 价格

模拟器支持

使用 dotenv 的环境配置可与本地 Cloud Functions 模拟器进行互操作。

使用本地 Cloud Functions 模拟器时,您可以通过设置 .env.local 文件来替换项目的环境变量。.env.local 的内容优先于 .env 和项目特定的 .env 文件。

例如,一个项目可以包含以下三个文件,这些文件中包含的用于开发和本地测试的值会略有不同:

.env .env.dev .env.local
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

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

  $ firebase emulators:start
  i  emulators: Starting emulators: functions
  # Starts emulator with following environment variables:
  #  PLANET=Earth
  #  AUDIENCE=Local Humans

Cloud Functions 模拟器中的 Secret 和凭据

Cloud Functions 模拟器支持使用 Secret 存储和访问敏感配置信息。默认情况下,模拟器将尝试使用应用默认凭据访问生产 Secret。在某些情况(例如 CI 环境)下,模拟器可能会由于权限限制而无法访问 Secret 值。

与 Cloud Functions 模拟器对环境变量的支持类似,您可以通过设置 .secret.local 文件来替换 Secret 值。这样,您就可以轻松地在本地测试函数,尤其是当您无法访问 Secret 值时。

从环境配置迁移

如果您一直将环境配置与 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

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

我们建议您在部署函数或将 .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);