将 Firebase 与 Next.js 应用集成

1. 准备工作

在此 Codelab 中,您将了解如何将 Firebase 与名为 Friends Eats 的 Next.js Web 应用相集成,该应用是一个餐厅评价网站。

FRIEND Eats Web 应用

完成后的 Web 应用提供了一些实用功能,展示了 Firebase 如何帮助您构建 Next.js 应用。这些功能包括:

  • 使用 Google 账号登录和退出功能:完成后的 Web 应用支持您使用 Google 账号登录和退出账号。用户登录和保留功能完全通过 Firebase Authentication 进行管理。
  • 图片:完成后的 Web 应用可让登录用户上传餐馆图片。图片素材资源存储在 Cloud Storage for Firebase 中。Firebase JavaScript SDK 提供了已上传图片的公开网址。然后,此公开网址将存储在 Cloud Firestore 内的相关餐馆文档中。
  • 评价:完成后的 Web 应用支持登录用户发布对餐厅的评价,其中包含星级评分和基于文本的消息。评价信息存储在 Cloud Firestore 中。
  • 过滤条件:完成后的 Web 应用可让登录用户根据类别、位置和价格过滤餐馆列表。您还可以自定义所使用的排序方法。系统会从 Cloud Firestore 访问数据,并根据所使用的过滤条件应用 Firestore 查询。

前提条件

  • 了解 Next.js 和 JavaScript 相关知识

学习内容

  • 如何将 Firebase 与 Next.js 应用路由器和服务器端渲染搭配使用。
  • 如何在 Cloud Storage for Firebase 中保留图片。
  • 如何在 Cloud Firestore 数据库中读取和写入数据。
  • 如何将“使用 Google 账号登录”用于 Firebase JavaScript SDK。

所需条件

  • Git
  • Java 开发套件
  • 最新的稳定版 Node.js
  • 您所选的浏览器(例如 Google Chrome)
  • 包含代码编辑器和终端的开发环境
  • 一个用于创建和管理 Firebase 项目的 Google 账号
  • 能够将 Firebase 项目升级为 Blaze 定价方案

2. 设置您的开发环境

此 Codelab 提供了应用的起始代码库,并依赖于 Firebase CLI。

下载仓库

  1. 在您的终端中,克隆此 Codelab 的 GitHub 代码库:
    git clone https://github.com/firebase/friendlyeats-web.git
    
  2. GitHub 代码库包含适用于多个平台的示例项目。不过,此 Codelab 仅使用 nextjs-start 目录。请注意以下目录:
    • nextjs-start:包含您在构建时所依据的起始代码。
    • nextjs-end:包含完成后的 Web 应用的解决方案代码。
  3. 在您的终端中,转到 nextjs-start 目录并安装必要的依赖项:
    cd friendlyeats-web/nextjs-start
    npm install
    

安装或更新 Firebase CLI

运行以下命令,验证是否已安装 Firebase CLI 且版本为 12.5.4 或更高版本:

firebase --version
  • 如果您安装了 Firebase CLI,但其版本不是 v12.5.4 或更高版本,请进行更新:
    npm update -g firebase-tools
    
  • 如果您没有安装 Firebase CLI,请进行安装:
    npm install -g firebase-tools
    

如果由于权限错误而无法安装 Firebase CLI,请参阅 npm 文档或使用其他安装选项

登录 Firebase

  1. 运行以下命令以登录 Firebase CLI:
    firebase login
    
  2. 根据您是否希望 Firebase 收集数据,请输入 YN
  3. 在浏览器中,选择您的 Google 账号,然后点击允许

3. 设置您的 Firebase 项目

在本部分中,您将设置一个 Firebase 项目,并向其关联一个 Firebase Web 应用。您还将设置示例 Web 应用使用的 Firebase 服务。

创建 Firebase 项目

  1. Firebase 控制台中,点击创建项目
  2. 输入您的项目名称文本框中,输入 FriendlyEats Codelab(或您所选的项目名称),然后点击继续
  3. 对于此 Codelab,您不需要使用 Google Analytics(分析),因此请关闭为此项目启用 Google Analytics(分析)选项。
  4. 点击 Create project
  5. 等待您的项目完成预配,然后点击继续
  6. 在 Firebase 项目中,前往项目设置。请记下您的项目 ID,因为稍后需要用到。此唯一标识符用于识别项目(例如在 Firebase CLI 中)。

向 Firebase 项目添加 Web 应用

  1. 前往 Firebase 项目中的项目概览页面,然后点击 e41f2efdd9539c31.png Web
  2. 应用别名文本框中,输入一个容易记住的应用别名,例如 My Next.js app
  3. 选中还为此应用设置 Firebase Hosting 复选框。
  4. 点击注册应用 > 下一步 > 下一步 > 继续前往控制台

升级您的 Firebase 定价方案

如需使用 Web 框架,您的 Firebase 项目必须采用 Blaze 定价方案,这意味着该项目与一个 Cloud Billing 账号相关联。

  • Cloud Billing 账号要求提供付款方式,例如信用卡。
  • 如果您刚开始接触 Firebase 和 Google Cloud,请确认您是否有资格获得 $300 赠金和免费试用 Cloud Billing 账号

但请注意,完成此 Codelab 应该不会产生任何实际费用。

如需将项目升级到 Blaze 方案,请按以下步骤操作:

  1. 在 Firebase 控制台中,选择升级您的方案
  2. 在对话框中,选择 Blaze 方案,然后按照屏幕上的说明将您的项目与 Cloud Billing 账号相关联。
    如果您需要创建 Cloud Billing 账号,则可能需要返回 Firebase 控制台中的升级流程以完成升级。

在 Firebase 控制台中设置 Firebase 服务

设置身份验证

  1. 在 Firebase 控制台中,前往身份验证
  2. 点击开始使用
  3. 其他提供商列中,点击 Google > 启用
  4. 项目的公开名称文本框中,输入一个容易记住的名称,例如 My Next.js app
  5. 项目的支持电子邮件地址下拉列表中,选择您的电子邮件地址。
  6. 点击保存

设置 Cloud Firestore

  1. 在 Firebase 控制台中,前往 Firestore
  2. 点击创建数据库 > 以测试模式开始 > 下一步
    在本 Codelab 的后面部分,您将添加安全规则来保护您的数据。在没有为数据库添加安全规则的情况下,请不要公开分发或公开应用。
  3. 使用默认位置或选择您所选的位置。
    对于真实应用,您需要选择靠近用户的位置。请注意,此位置以后无法更改,并且它也会自动成为您的默认 Cloud Storage 存储桶的位置(下一步)。
  4. 点击完成

设置 Cloud Storage for Firebase

  1. 在 Firebase 控制台中,前往 Storage
  2. 点击开始使用 > 以测试模式开始 > 下一步
    在本 Codelab 的后面,您将添加安全规则来保护您的数据。在未为您的存储桶添加安全规则的情况下,请不要公开分发或公开应用。
  3. 您的存储桶的位置应该已经处于选中状态(由于在上一步中设置了 Firestore)。
  4. 点击完成

4. 查看起始代码库

在本部分中,您将复习应用起始代码库中的几个部分,以便在此 Codelab 中向这些部分添加功能。

文件夹和文件结构

下表简要介绍了应用的文件夹和文件结构:

文件夹和文件

说明

src/components

适用于过滤条件、标题、餐馆详细信息和评价的 React 组件

src/lib

不一定绑定到 React 或 Next.js 的实用函数

src/lib/firebase

Firebase 专属代码和 Firebase 配置

public

Web 应用中的静态资源,例如图标

src/app

使用 Next.js 应用路由器进行路由

src/app/restaurant

API 路由处理程序

package.jsonpackage-lock.json

使用 npm 的项目依赖项

next.config.js

Next.js 专属配置(已启用服务器操作)

jsconfig.json

JavaScript 语言服务配置

服务器和客户端组件

该应用是使用应用路由器的 Next.js Web 应用。整个应用都会使用服务器渲染。例如,src/app/page.js 文件是负责主页面的服务器组件。src/components/RestaurantListings.jsx 文件是一个客户端组件,由文件开头的 "use client" 指令表示。

Import 语句

您可能会注意到如下 import 语句:

import RatingPicker from "@/src/components/RatingPicker.jsx";

应用使用 @ 符号来避免复杂的相对导入路径,这是通过路径别名实现的。

Firebase 专属 API

所有 Firebase API 代码都封装在 src/lib/firebase 目录中。然后,各个 React 组件会从 src/lib/firebase 目录导入封装的函数,而不是直接导入 Firebase Functions 函数。

模拟数据

模拟餐厅和评价数据包含在 src/lib/randomData.js 文件中。该文件中的数据会汇编在 src/lib/fakeRestaurants.js 文件的代码中。

5. 使用 Firebase Hosting 模拟器设置本地托管

在本部分中,您将使用 Firebase Hosting 模拟器在本地运行 Next.js Web 应用。

完成本部分后,Firebase Hosting 模拟器会为您运行 Next.js 应用,因此您无需在模拟器的单独进程中运行 Next.js。

下载并使用 Firebase 服务账号

您将在此 Codelab 中构建的 Web 应用通过 Next.js 使用服务器端渲染。

我们使用 Node.js 版 Firebase Admin SDK 确保安全规则通过服务器端代码正常运行。如需在 Firebase Admin 中使用 API,您需要从 Firebase 控制台下载并使用 Firebase 服务账号

  1. 在 Firebase 控制台中,前往项目设置中的服务账号页面。
  2. 点击生成新的私钥 > 生成密钥
  3. 将文件下载到文件系统后,获取该文件的完整路径。
    例如,如果您将文件下载到“下载”目录,则完整路径可能如下所示:/Users/me/Downloads/my-project-id-firebase-adminsdk-123.json
  4. 在终端中,将 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为您下载私钥的路径。在 Unix 环境中,该命令可能如下所示:
    export GOOGLE_APPLICATION_CREDENTIALS="/Users/me/Downloads/my-project-id-firebase-adminsdk-123.json"
    
  5. 请将此终端保持打开状态,并在本 Codelab 的剩余部分中使用它,因为如果启动新的终端会话,环境变量可能会丢失。
    如果您打开一个新的终端会话,则必须重新运行上一条命令。

将 Firebase 配置添加到 Web 应用代码中

  1. 在 Firebase 控制台中,前往项目设置
  2. SDK 设置和配置窗格中,找到 firebaseConfig 变量,然后复制其属性和值。
  3. 在代码编辑器中打开 .env 文件,然后使用 Firebase 控制台中的配置值填充环境变量值。
  4. 在文件中,将现有属性替换为您复制的属性。
  5. 保存文件。

使用 Firebase 项目初始化 Web 应用

如需将该 Web 应用关联到您的 Firebase 项目,请按以下步骤操作:

  1. 在您的终端中,确保在 Firebase 中启用了 Web 框架:
    firebase experiments:enable webframeworks
    
  2. 初始化 Firebase:
    firebase init
    
  3. 选择以下选项:
    • Firestore:为 Firestore 配置安全规则和索引文件
    • Hosting:为 Firebase Hosting 配置文件,并(可选)设置 GitHub 操作部署
    • 存储:为 Cloud Storage 配置安全规则文件
    • 模拟器:为 Firebase 产品设置本地模拟器
  4. 选择使用现有项目,然后输入您之前记下的项目 ID。
  5. 对于所有后续问题,都选择默认值,直到出现您希望在哪个区域托管服务器端内容(如适用)?这一问题。终端会显示一条消息,提示它在当前目录中检测到现有的 Next.js 代码库。
  6. 对于您希望在哪个区域托管服务器端内容(如适用?)这一问题,请选择您之前为 Firestore 和 Cloud Storage 选择的位置。
  7. 对于所有后续问题,请选择默认值,直到出现您想要设置哪些 Firebase 模拟器?这一问题。对于此问题,请选择 Functions 模拟器Hosting 模拟器
  8. 请为所有其他问题选择默认值。

部署安全规则

该代码已经为 Firestore 和 Cloud Storage for Firebase 设置了一组安全规则。部署安全规则后,数据库和存储桶中的数据可以得到更好的保护,避免遭到滥用。

  1. 如需部署这些安全规则,请在终端中运行以下命令:
    firebase deploy --only firestore:rules,storage
    
  2. 如果系统询问您:"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?",请选择

启动 Hosting 模拟器

  1. 在终端中,启动 Hosting 模拟器:
    firebase emulators:start --only hosting
    
    终端会返回包含 Hosting 模拟器的端口进行响应,例如 http://localhost:5000/

显示 Hosting 模拟器已准备就绪的终端

  1. 在浏览器中,使用 Firebase Hosting 模拟器导航到该网址。
  2. 如果您在网页中看到像 "Error: Firebase session cookie has incorrect..." 这样开头的错误,则需要删除 localhost 环境中的所有 Cookie。为此,请按照删除 Cookie | 开发者工具文档中的说明执行操作。

Cookie 会话错误

在开发者工具中删除 Cookie

现在,您可以看到初始 Web 应用!即使您通过 localhost 网址查看 Web 应用,该应用仍会使用您在控制台中配置的实际 Firebase 服务。

6. 向 Web 应用添加身份验证功能

在本部分中,您将向 Web 应用添加身份验证,以便登录该应用。

实现登录和退出功能

  1. src/lib/firebase/auth.js 文件中,将 onAuthStateChangedsignInWithGooglesignOut 函数替换为以下代码:
export function onAuthStateChanged(cb) {
        return _onAuthStateChanged(auth, cb);
}

export async function signInWithGoogle() {
        const provider = new GoogleAuthProvider();

        try {
                await signInWithPopup(auth, provider);
        } catch (error) {
                console.error("Error signing in with Google", error);
        }
}

export async function signOut() {
        try {
                return auth.signOut();
        } catch (error) {
                console.error("Error signing out with Google", error);
        }
}

此代码使用以下 Firebase API:

Firebase API

说明

GoogleAuthProvider

创建 Google 身份验证提供方实例。

signInWithPopup

启动基于对话框的身份验证流程。

auth.signOut

退出用户账号。

src/components/Header.jsx 文件中,代码已经调用了 signInWithGooglesignOut 函数。

  1. 在 Web 应用中,刷新页面,然后点击使用 Google 账号登录。该 Web 应用无法更新,因此不确定登录是否成功。

订阅身份验证更改

如需订阅身份验证更改,请按以下步骤操作:

  1. 导航到 src/components/Header.jsx 文件。
  2. 将整个 useUserSession 函数替换为以下代码:
function useUserSession(initialUser) {
        // The initialUser comes from the server through a server component
        const [user, setUser] = useState(initialUser);
        const router = useRouter();

        useEffect(() => {
                const unsubscribe = onAuthStateChanged(authUser => {
                        setUser(authUser);
                });
                return () => {
                        unsubscribe();
                };
        }, []);

        useEffect(() => {
                onAuthStateChanged(authUser => {
                        if (user === undefined) return;
                        if (user?.email !== authUser?.email) {
                                router.refresh();
                        }
                });
        }, [user]);

        return user;
}

onAuthStateChanged 函数指定身份验证状态发生更改时,此代码使用 React state 钩子来更新用户。

验证更改

src/app/layout.js 文件中的根布局会渲染该标头,并传入用户(如有)作为属性。

<Header initialUser={currentUser?.toJSON()} />

这意味着,<Header> 组件会在服务器运行时渲染用户数据(如有)。初始网页加载后,如果在页面生命周期内有任何身份验证更新,onAuthStateChanged 处理程序会处理这些更新。

接下来,您可以测试该 Web 应用并验证您构建的内容。

如需验证新的身份验证行为,请按以下步骤操作:

  1. 在浏览器中,刷新 Web 应用。您的显示名称会显示在标头中。
  2. 退出并重新登录。该网页会实时更新,且无需刷新网页。您可以针对不同用户重复此步骤。
  3. 可选:右键点击该 Web 应用,选择查看网页源代码,然后搜索显示名称。该名称会在从服务器返回的原始 HTML 源代码中显示。

7. 查看餐厅信息

该 Web 应用包含餐馆和评价的模拟数据

添加一家或多家餐馆

如需将模拟餐厅数据插入本地 Cloud Firestore 数据库,请按以下步骤操作:

  1. 在 Web 应用中,选择 2cf67d488d8e6332.png > 添加示例餐馆
  2. 在 Firebase 控制台的 Firestore 数据库页面上,选择餐厅。您会在餐馆集合中看到顶级文档,其中每个文档都代表一家餐馆。
  3. 点击几个文档即可浏览餐馆文档的属性。

显示餐馆列表

您的 Cloud Firestore 数据库现在包含 Next.js Web 应用可以显示的餐馆。

如需定义数据提取代码,请按以下步骤操作:

  1. src/app/page.js 文件中,找到 <Home /> 服务器组件,并查看对 getRestaurants 函数的调用,该函数用于在服务器运行时检索餐馆列表。您将在以下步骤中实现 getRestaurants 函数。
  2. src/lib/firebase/firestore.js 文件中,将 applyQueryFiltersgetRestaurants 函数替换为以下代码:
function applyQueryFilters(q, { category, city, price, sort }) {
        if (category) {
                q = query(q, where("category", "==", category));
        }
        if (city) {
                q = query(q, where("city", "==", city));
        }
        if (price) {
                q = query(q, where("price", "==", price.length));
        }
        if (sort === "Rating" || !sort) {
                q = query(q, orderBy("avgRating", "desc"));
        } else if (sort === "Review") {
                q = query(q, orderBy("numRatings", "desc"));
        }
        return q;
}

export async function getRestaurants(filters = {}) {
        let q = query(collection(db, "restaurants"));

        q = applyQueryFilters(q, filters);
        const results = await getDocs(q);
        return results.docs.map(doc => {
                return {
                        id: doc.id,
                        ...doc.data(),
                        // Only plain objects can be passed to Client Components from Server Components
                        timestamp: doc.data().timestamp.toDate(),
                };
        });
}
  1. 刷新 Web 应用。餐馆图片以图块的形式显示在页面上。

验证餐馆商家信息是否在服务器运行时加载

使用 Next.js 框架时,在服务器运行时或客户端运行时加载数据的时间可能不明显。

如需验证餐厅商家信息是否在服务器运行时加载,请按以下步骤操作:

  1. 在 Web 应用中,打开开发者工具并停用 JavaScript

在开发者工具中停用 JavaScipt

  1. 刷新 Web 应用。餐馆商家信息仍会加载。服务器响应中会返回餐馆信息。当 JavaScript 处于启用状态时,餐厅信息会通过客户端 JavaScript 代码进行水合处理。
  2. 在开发者工具中,重新启用 JavaScript

使用 Cloud Firestore 快照监听器监听餐馆更新

在上一部分中,您了解了如何从 src/app/page.js 文件加载初始餐馆集。src/app/page.js 文件是一个服务器组件,并在服务器上呈现,包括 Firebase 数据提取代码。

src/components/RestaurantListings.jsx 文件是一个客户端组件,可配置为水合服务器渲染的标记。

如需配置 src/components/RestaurantListings.jsx 文件以水合服务器渲染的标记,请按以下步骤操作:

  1. src/components/RestaurantListings.jsx 文件中,观察已经为您编写的以下代码:
useEffect(() => {
        const unsubscribe = getRestaurantsSnapshot(data => {
                setRestaurants(data);
        }, filters);

        return () => {
                unsubscribe();
        };
}, [filters]);

此代码会调用 getRestaurantsSnapshot() 函数,类似于您在上一步中实现的 getRestaurants() 函数。不过,此快照函数提供了一种回调机制,以便在每次餐馆的集合发生更改时都会调用该回调。

  1. src/lib/firebase/firestore.js 文件中,将 getRestaurantsSnapshot() 函数替换为以下代码:
export function getRestaurantsSnapshot(cb, filters = {}) {
        if (typeof cb !== "function") {
                console.log("Error: The callback parameter is not a function");
                return;
        }

        let q = query(collection(db, "restaurants"));
        q = applyQueryFilters(q, filters);

        const unsubscribe = onSnapshot(q, querySnapshot => {
                const results = querySnapshot.docs.map(doc => {
                        return {
                                id: doc.id,
                                ...doc.data(),
                                // Only plain objects can be passed to Client Components from Server Components
                                timestamp: doc.data().timestamp.toDate(),
                        };
                });

                cb(results);
        });

        return unsubscribe;
}

通过 Firestore 数据库页面所做的更改现在会实时反映在 Web 应用中。

  1. 在 Web 应用中,选择 27ca5d1e8ed8adfe.png > 添加示例餐馆。如果正确实现快照功能,餐馆会实时显示,而无需刷新网页。

8. 保存 Web 应用中的用户数据

  1. src/lib/firebase/firestore.js 文件中,将 updateWithRating() 函数替换为以下代码:
const updateWithRating = async (
        transaction,
        docRef,
        newRatingDocument,
        review
) => {
        const restaurant = await transaction.get(docRef);
        const data = restaurant.data();
        const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
        const newSumRating = (data?.sumRating || 0) + Number(review.rating);
        const newAverage = newSumRating / newNumRatings;

        transaction.update(docRef, {
                numRatings: newNumRatings,
                sumRating: newSumRating,
                avgRating: newAverage,
        });

        transaction.set(newRatingDocument, {
                ...review,
                timestamp: Timestamp.fromDate(new Date()),
        });
};

此代码会插入一个表示新评价的新 Firestore 文档。该代码还会更新代表餐馆的现有 Firestore 文档,使其包含评分数量和平均计算评分的更新后数据。

  1. 将整个 addReviewToRestaurant() 函数替换为以下代码:
export async function addReviewToRestaurant(db, restaurantId, review) {
        if (!restaurantId) {
                throw new Error("No restaurant ID was provided.");
        }

        if (!review) {
                throw new Error("A valid review has not been provided.");
        }

        try {
                const docRef = doc(collection(db, "restaurants"), restaurantId);
                const newRatingDocument = doc(
                        collection(db, `restaurants/${restaurantId}/ratings`)
                );

                await runTransaction(db, transaction =>
                        updateWithRating(transaction, docRef, newRatingDocument, review)
                );
        } catch (error) {
                console.error(
                        "There was an error adding the rating to the restaurant.",
                        error
                );
                throw error;
        }
}

实现 Next.js 服务器操作

Next.js 服务器操作提供了方便的 API 来访问表单数据(例如 data.get("text")),以从表单提交载荷中获取文本值。

如需使用 Next.js 服务器操作处理评价表单提交,请按以下步骤操作:

  1. src/components/ReviewDialog.jsx 文件中,找到 <form> 元素中的 action 属性。
<form action={handleReviewFormSubmission}>

action 属性值是指您将在下一步中实现的函数。

  1. src/app/actions.js 文件中,将 handleReviewFormSubmission() 函数替换为以下代码:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
        const { app } = await getAuthenticatedAppForUser();
        const db = getFirestore(app);

        await addReviewToRestaurant(db, data.get("restaurantId"), {
                text: data.get("text"),
                rating: data.get("rating"),

                // This came from a hidden form field.
                userId: data.get("userId"),
        });
}

添加对餐厅的评价

您实现了对评价提交功能的支持,因此现在可以验证您的评价是否已正确插入到 Cloud Firestore 中。

如需添加评价并验证其是否已插入 Cloud Firestore,请按以下步骤操作:

  1. 在 Web 应用中,从首页选择一家餐馆。
  2. 在餐馆页面上,点击 3e19beef78bb0d0e.png
  3. 请选择星级评分。
  4. 撰写评价。
  5. 点击提交。您的评价会显示在评价列表的顶部。
  6. 在 Cloud Firestore 中,在添加文档窗格中搜索您评价过的餐馆的文档并将其选中。
  7. 启动集合窗格中,选择评分
  8. 添加文档窗格中,找到您的评价的文档,验证其是否已按预期插入。

Firestore 模拟器中的文档

9. 保存用户从 Web 应用上传的文件

在本部分中,您将添加一项功能,以便在登录时替换与餐馆关联的图片。您将图片上传到 Firebase Storage,并更新 Cloud Firestore 文档中代表该餐馆的图片网址。

如需保存用户通过该 Web 应用上传的文件,请按以下步骤操作:

  1. src/components/Restaurant.jsx 文件中,观察用户上传文件时运行的代码:
async function handleRestaurantImage(target) {
        const image = target.files ? target.files[0] : null;
        if (!image) {
                return;
        }

        const imageURL = await updateRestaurantImage(id, image);
        setRestaurant({ ...restaurant, photo: imageURL });
}

无需进行任何更改,但您将在以下步骤中实现 updateRestaurantImage() 函数的行为。

  1. src/lib/firebase/storage.js 文件中,将 updateRestaurantImage()uploadImage() 函数替换为以下代码:
export async function updateRestaurantImage(restaurantId, image) {
        try {
                if (!restaurantId)
                        throw new Error("No restaurant ID has been provided.");

                if (!image || !image.name)
                        throw new Error("A valid image has not been provided.");

                const publicImageUrl = await uploadImage(restaurantId, image);
                await updateRestaurantImageReference(restaurantId, publicImageUrl);

                return publicImageUrl;
        } catch (error) {
                console.error("Error processing request:", error);
        }
}

async function uploadImage(restaurantId, image) {
        const filePath = `images/${restaurantId}/${image.name}`;
        const newImageRef = ref(storage, filePath);
        await uploadBytesResumable(newImageRef, image);

        return await getDownloadURL(newImageRef);
}

我们已为您实现 updateRestaurantImageReference() 函数。此函数使用更新后的图片网址更新 Cloud Firestore 中现有的餐馆文档。

验证图片上传功能

如需验证图片是否按预期上传,请按以下步骤操作:

  1. 在 Web 应用中,验证您已登录,并选择一家餐馆。
  2. 点击 7067eb41fea41ff0.png,然后从文件系统中上传图片。您的映像将离开本地环境并上传到 Cloud Storage。图片会在上传后立即显示。
  3. 前往 Cloud Storage for Firebase。
  4. 前往代表该餐馆的文件夹。您上传的图片已在文件夹中。

6cf3f9e2303c931c.png

10. 总结

恭喜!您了解了如何使用 Firebase 为 Next.js 应用添加特性和功能。具体来说,您使用了以下各项:

了解详情