如果您曾使用 Firebase JS SDK 或其他 Firebase 用戶端 SDK,可能熟悉 FirebaseApp 介面,以及如何使用該介面設定應用程式執行個體。為方便在伺服器端執行類似作業,Firebase 提供 FirebaseServerApp。
FirebaseServerApp 是 FirebaseApp 的變體,適用於伺服器端算繪 (SSR) 環境。其中包含可延續 Firebase 工作階段的工具,能跨越用戶端轉譯 (CSR) / 伺服器端轉譯 (SSR) 的界線。這些工具和策略有助於強化使用 Firebase 建構,並部署在 Google 環境 (例如 Firebase App Hosting) 的動態網頁應用程式。
FirebaseServerApp 可用來:
- 在「使用者」情境中執行伺服器端程式碼,與擁有完整管理權限的 Firebase Admin SDK 形成對比。
- 在 SSR 環境中啟用 App Check。
- 繼續在用戶端建立的 Firebase Auth 工作階段。
FirebaseServerApp 生命週期
伺服器端轉譯 (SSR) 架構和其他非瀏覽器執行階段 (例如雲端工作者),會跨多個執行作業重複使用資源,藉此縮短初始化時間。FirebaseServerApp 採用參照計數機制,可因應這類環境。如果應用程式使用與先前 initializeServerApp 相同的參數叫用 initializeServerApp,則會收到已初始化的相同 FirebaseServerApp 執行個體。這可減少不必要的初始化負擔和記憶體配置。在 FirebaseServerApp 執行個體上叫用 deleteApp 時,系統會減少參照計數,並在參照計數達到零後釋出執行個體。
正在清除 FirebaseServerApp 個執行個體
您可能很難判斷何時要在 FirebaseServerApp 執行個體上呼叫 deleteApp,尤其是在同時執行多項非同步作業時。FirebaseServerAppSettings 的 releaseOnDeref 欄位有助於簡化這項作業。如果您將 releaseOnDeref 參照指派給具有要求範圍生命週期的物件 (例如 SSR 要求的標頭物件),則當架構回收標頭物件時,FirebaseServerApp 會減少其參照計數。這會自動清除 FirebaseServerApp 執行個體。
以下是 releaseOnDeref 的使用範例:
/// Next.js
import { headers } from 'next/headers'
import { FirebaseServerAppSettings, initializeServerApp} from "firebase/app";
export default async function Page() {
const headersObj = await headers();
let appSettings: FirebaseServerAppSettings = {};
appSettings.releaseOnDeref = headersObj;
const serverApp = initializeServerApp(firebaseConfig, appSettings);
...
}
繼續執行在用戶端建立的已驗證工作階段
使用驗證 ID 權杖初始化 FirebaseServerApp 執行個體時,系統會在用戶端轉譯 (CSR) 和伺服器端轉譯 (SSR) 環境之間,建立已驗證使用者工作階段的橋接。使用包含驗證 ID 權杖的 FirebaseServerApp 物件初始化 Firebase Auth SDK 執行個體時,系統會在初始化時嘗試登入使用者,應用程式不需要叫用任何登入方式。
提供驗證 ID 權杖後,應用程式就能在用戶端使用任何驗證登入方式,確保工作階段在伺服器端繼續進行,即使是需要使用者互動的登入方式也一樣。此外,這項功能還可將密集作業 (例如經過驗證的 Firestore 查詢) 卸載至伺服器,進而提升應用程式的算繪效能。
/// Next.js
import { initializeServerApp } from "firebase/app";
import { getAuth } from "firebase/auth";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
authIdToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
const serverAuth = getAuth(serverApp);
// FirebaseServerApp and Auth will now attempt
// to sign in the current user based on provided
// authIdToken.
在 SSR 環境中使用 App Check
App Check 強制執行功能仰賴 App Check SDK 執行個體,Firebase SDK 會使用該執行個體在內部呼叫 getToken。產生的權杖會包含在傳送至所有 Firebase 服務的要求中,讓後端驗證應用程式。
不過,App Check SDK 需要瀏覽器才能存取特定經驗法則來驗證應用程式,因此無法在伺服器環境中初始化。
FirebaseServerApp 提供替代方案。如果在 FirebaseServerApp 初始化期間提供用戶端產生的 App Check 權杖,Firebase 產品 SDK 會在叫用 Firebase 服務時使用該權杖,因此不需要 App Check SDK 執行個體。
/// Next.js
import { initializeServerApp } from "firebase/app";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
appCheckToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
// The App Check token will now be appended to all Firebase service requests.
將用戶端權杖傳遞至伺服器端算繪階段
如要將經過驗證的 Auth ID 權杖 (和 App Check 權杖) 從用戶端傳輸至伺服器端轉譯 (SSR) 階段,請使用 Service Worker。這種做法會攔截觸發 SSR 的擷取要求,並將權杖附加至要求標頭。
如需 Firebase Auth Service Worker 的參考實作,請參閱「使用 Service Worker 進行工作階段管理」。另請參閱伺服器端變更,瞭解如何從標頭剖析這些權杖,以便在 FirebaseServerApp 初始化中使用。
在 SSR 環境中使用 Firestore
使用伺服器端轉譯 (SSR) 建構網頁應用程式時,通常需要在伺服器和用戶端之間共用資料,以最佳化效能和使用者體驗。Firestore SDK 提供序列化工具,可讓您在伺服器上擷取快照和特定資料類型,並直接傳遞至用戶端元件。這個程序可讓用戶端使用 SSR 階段預先擷取的資料來補充狀態,避免重複擷取。此外,您也可以從這些序列化狀態轉換為即時事件監聽器,確保應用程式與資料庫保持同步。
本節說明如何在用戶端元件中,重複使用伺服器端轉譯 (SSR) 階段擷取的資料。
序列化資料類型
某些 Firestore 資料類型提供 toJSON 方法,可將資料轉換為可序列化的格式。包括 Bytes、GeoPoint、Timestamp 和 VectorValue 等物件的例項。
取得 JSON 格式的資料後,您可以透過標準架構機制,將資料從伺服器傳遞至用戶端,或做為跨越分界元件的參數。例如:
import {
Bytes
} from 'firebase/firestore';
const BYTES_DATA = new Uint8Array([0, 1, 2, 3, 4, 5]);
const bytes = Bytes.fromUint8Array(BYTES_DATA);
const bytesJSON = bytes.toJSON();
反序列化資料類型
Firestore 資料類型包含靜態方法 fromJSON,可將序列化資料轉換為可操作的 Firestore 資料類型。
舉例來說,以下程式碼會將 Bytes 資料類型反序列化:
import {
Bytes
} from 'firebase/firestore';
// Assuming the same `bytesJSON` variable from the previous example.
const deserializedBytes = Bytes.fromJSON(bytesJSON);
序列化及反序列化 Firestore 快照
與 Firestore 資料類型類似,您可以使用 toJSON 序列化 DocumentSnapshot 和 QuerySnapshot 的例項。不過,如要反序列化,您必須使用獨立函式 documentSnapshotFromJSON 和 querySnapshotFromJSON,而非靜態 fromJSON 方法。
舉例來說,query 作業的 querySnapshot 結果可以使用 toJSON 方法序列化:
import {
collection,
getDocs,
query,
querySnapshotFromJSON
} from 'firebase/firestore';
// Assuming a configured instance of Firestore in the variable `firestore`.
const queryRef = query(collection(firestore, QUERY_PATH));
const querySnapshot = await getDocs(queryRef);
const querySnapshotJson = querySnapshot.toJSON();
接著,這項資料可以反序列化:
import {
querySnapshotFromJSON
} from 'firebase/firestore';
// deserializedSnapshot is an object of type QuerySnapshot:
const deserializedSnapshot =
querySnapshotFromJSON(firestore, querySnapshotJson);
具有序列化快照的監聽器
雖然在 SSR 階段查詢的資料對初始 CSR 轉譯很有價值,但您可能仍需監控 Firestore 服務,以便即時更新該資訊。
如果應用程式需要這些即時更新,您可以使用 onSnapshotResume 函式,以序列化的 Snapshot 資料初始化 Firestore SnapshotListener。例如:
const observer = {
next: (qs) => {
console.log("onSnapshot invoked: ", qs.data());
},
error: (e) => {
console.log("error callback invoked: ", e.toString());
}
};
const unsubscribe = onSnapshotResume(firestore, querySnapshotJson, observer);