如果您曾使用 Firebase JS SDK 或其他 Firebase 用戶端 SDK,可能已熟悉 FirebaseApp 介面,以及如何使用該介面設定應用程式例項。為方便在伺服器端執行類似作業,Firebase 提供 FirebaseServerApp。
FirebaseServerApp 是 FirebaseApp 的變體,適用於伺服器端算繪 (SSR) 環境。這項功能包含的工具可繼續執行跨用戶端轉譯 (CSR) / 伺服器端轉譯的 Firebase 工作階段。這些工具和策略有助於強化以 Firebase 建構的動態網頁應用程式,並部署在 Firebase App Hosting 等 Google 環境中。
FirebaseServerApp 可用來:
- 在使用者環境中執行伺服器端程式碼,與具有完整管理權限的 Firebase Admin SDK 不同。
- 在 SSR 環境中啟用 App Check。
- 繼續在用戶端建立的 Firebase 驗證工作階段。
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);
...
}
繼續執行在用戶端建立的已驗證工作階段
以 Auth ID 權杖初始化 FirebaseServerApp 例項時,系統會啟用用戶端轉譯 (CSR) 和伺服器端轉譯 (SSR) 環境之間的已驗證使用者工作階段橋接。使用含有 Auth ID 權杖的 FirebaseServerApp 物件初始化的 Firebase Auth SDK 執行個體,會在初始化時嘗試登入使用者,應用程式不必叫用任何登入方法。
提供 Auth ID 權杖後,應用程式就能在用戶端使用任何 Auth 登入方法,確保工作階段在伺服器端持續進行,即使是需要使用者互動的登入方法也一樣。此外,這項功能可將需要大量運算的作業 (例如經過驗證的 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 強制執行功能會使用 Firebase SDK 內部呼叫 getToken 的 App Check SDK 執行個體。然後,系統會將產生的權杖納入所有 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 驗證 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);