通常,您需要對功能進行其他配置,例如第三方 API 密鑰或可調整設置。 Firebase SDK for Cloud Functions 提供內置環境配置,使您可以輕鬆地為項目存儲和檢索此類數據。
您可以選擇以下三個選項:
- 參數化配置(大多數場景推薦)。這提供了強類型環境配置以及在部署時驗證的參數,從而防止錯誤並簡化調試。
- 基於文件的環境變量配置。通過這種方法,您可以手動創建dotenv文件來加載環境變量。
- 使用 Firebase CLI 和
functions.config
進行運行時環境配置(僅限 Cloud Functions(第一代))。
對於大多數用例,建議參數化配置。此方法使配置值在運行時和部署時都可用,並且除非所有參數都具有有效值,否則部署將被阻止。相反,環境變量的配置在部署時不可用。
參數化配置
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
.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
— 運行該函數的雲項目。 -
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_ 開頭的鍵
- 以下列表中的任意鍵:
- 雲運行時配置
- 入口點
- GCP_PROJECT
- GCLOUD_PROJECT
- GOOGLE_CLOUD_PROJECT
- FUNCTION_TRIGGER_TYPE
- 函數名稱
- FUNCTION_MEMORY_MB
- FUNCTION_TIMEOUT_SEC
- 函數標識
- FUNCTION_地區
- 功能_目標
- 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 個有效的 Secret版本。這意味著您每月可以在 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
命令。每個鍵都可以使用句點命名空間,將相關配置分組在一起。請記住,鍵中僅接受小寫字符;不允許使用大寫字符。
例如,要存儲“Some Service”的客戶端 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);