手把手教你Supabase,让前端轻松搞定后端 😉(下)

4,880 阅读8分钟

一、前言

当我们开发一个应用程序的时候,通常需要前端和后端各司其职并紧密协作。然而,当一个前端开发者想要独立开发应用时,后端开发的语言和逻辑可能是一片陌生的领域,这就会导致项目充满挑战甚至无法开展,前端必须先了解相关领域的知识才能继续推进。尽管我们能够使用 Node.js 等技术来进行后端开发,但依旧存在额外的复杂性和学习曲线。幸运的是,Supabase 的出现为前端开发者提供了一种全新的全栈开发方式。 

🎉 无需后端开发,现成后端能力 🎉

Supabase 不仅提供了数据库服务,也是一个全功能的后端服务平台。通过 Supabase,我们不再受限于传统的前后端分离模式,无需编写复杂的后端逻辑,可以直接在前端代码中进行数据库操作。这意味着,即使是没有后端开发背景的前端开发者,也能够独立构建出功能完备的全栈应用,实现从前端到后端的无缝开发体验。本文旨在为读者提供一个全面的 Supabase 使用指南,我们将通过一个简单的项目示例来详细介绍如何使用 Supabase,包括数据库的增删改查、用户认证、文件存储、实时订阅等功能,让我们一起开始探索 Supabase 带来的无限可能吧 🏄 文章分为上下两篇,当前为“下篇”内容:

  • 上篇:【基础】介绍 Supabsse 的项目初始化和数据库增删改查操作;
  • 下篇:【进阶】介绍 Supabase 的文件上传、用户认证和实时订阅功能;

P.S. Supabase 并不是说让前端来代替后端,在复杂应用场景下后端依旧是不可或缺的核心角色,对于轻量应用而言 Supabase 不失为一种选择,杠就是你对 😊

二、Supabase 是什么?

1.png

Supabase 是 Firebase 的开源替代品,是一个后端即服务(BaaS)平台,其允许开发者快速构建和部署应用程序,而无需担心底层基础设施的复杂性。Supabase 当前有六大核心功能(本文主要关注前 4 个核心能力):

2.svg

  • Database:Supabase 使用 PostgreSQL 作为其核心数据库;
  • Authentication:Supabase 内置了强大的用户管理系统,支持多种认证方式;
  • Storage:Supabase 提供具有无限扩展性的开源对象存储,适用于任何文件类型;
  • RealTime:Supabase 支持实时订阅功能,允许开发者订阅各种变化;
  • Edge Functions:Supabase 支持轻松创建、部署和监控分布在全球边缘的无服务器函数;
  • Vector:Supabase 还提供了向量数据库,为 AI 应用赋能。

Supabase 支持广泛的编程语言,其官方提供了 Javascript/Typescript 和 Flutter 等版本,在社区层面提供了 C#、Go、Java、Python、Ruby、Swift、Kotlin 等各种版本,可在 Github 中找到对应内容,这种多语言支持使得不同背景的开发者都能够轻松地将 Supabase 集成到他们的项目中。在前端框架的兼容性方面,Supabase 同样表现出色。无论你是使用 Next.js、React、Vue、NuxtJS、SvelteKit 还是 SolidJS,Supabase 都能提供无缝的集成体验,这种全面的前端支持确保了开发者可以根据自己的技术栈和偏好选择合适的框架,同时享受到 Supabase 提供的便利。更值得一提的是,Supabase 是一个开源产品,这意味着开发者不仅可以在 Supabase 的官方平台上创建和管理项目,还可以选择在本地进行私有化部署 🎉 这种灵活性为企业提供了一个安全、可控的后端解决方案,同时也让个人开发者能够根据自己的需求定制服务。

三、项目教程

编组.png

上篇回顾:项目初始化 & 数据库增删改查,手把手教你Supabase,让前端轻松搞定后端 😉(上)

3.4 文件存储

Supabase 除了提供 PostgreSQL 数据库之外,还提供了文件存储的能力,S3 Compatible Object Store,其适用于任何文件类型。在本项目中,我们通过支持上传商品概览图来介绍 Supabase 的文件存储功能。文件存储相关 API 可参考 👉 官方文档

3.4.1 Bucket 初始化

首先,我们进入 Storage 面板,然后创建一个名为“products”的桶(Bucket)。创建成功后,我们可以尝试手动上传一个图片文件。与上文一样,在进行用户认证之前,我们对桶先添加允许上传文件的 policies 以便我们开发使用。

编组 9.png

3.4.2 文件上传

在本项目中,我们首先会判断上传的数据中是否有文件,如果有文件会先上传文件获取文件的地址,然后将相关数据结合文件地址一起再上传或更新。

编组 10.png

// 上传文件
const updateFile = async (fileData: File) => {
  if (!fileData || !(fileData instanceof File)) {
    return "";
  }
  // 获取文件名
  const file_path = `${Math.random()}-${fileData.name}`.replaceAll("/", "").replaceAll("%", "");
  // 上传文件
  const { data, error } = await supabase.storage.from("products").upload(file_path, fileData);
  // 处理失败
  if (error) {
    throw new Error(error.message);
  }
  if (data.fullPath) {
    return `${supabaseUrl}/storage/v1/object/public/${data.fullPath}`;
  }
  return "";
};

// 增
export const createProduct = async (createProduct: CreateProductData) => {
  // 第一步先判断是否有文件,如果有先上传文件得到文件地址
  if (createProduct.pictureFile) {
    const pictureUrl = await updateFile(createProduct.pictureFile);
    createProduct.pictureUrl = pictureUrl;
  }
  delete createProduct.pictureFile;
  // 第二步将数据插入数据库
  const { data, error } = await supabase.from("products").insert([createProduct]).select().single();
  if (error) {
    throw new Error(error.message);
  }
  return data;
};

3.5 用户认证

Supabase 提供了功能强大的用户管理系统,内置身份验证、授权和用户管理等,无需任何额外的工作即可使用。除了常规的邮箱和电话注册方式之外,还支持 Apple、Github、Figma、Google 等多种方式。在本项目中,我们选择邮箱作为注册方式。用户认证的 API 可参考 👉 官方文档

编组 11.png

3.5.1 账户注册

当我们通过表单提交账户注册后,账户并不会直接注册成功,系统会向注册邮箱发送一份验证邮件,点击邮件的验证链接才会真正注册成功。

编组 12.png

// 账户注册
export const signUp = async ({ email, password }: { email: string; password: string }) => {
  const { data: user, error } = await supabase.auth.signUp({
    email,
    password,
  });
  if (error) throw new Error(error.message);
  return user;
};

邮箱验证也支持验证码等方式来校验,API 可参考官方文档,邮箱发送内容可在 Email Template 页面中进行更改,选择.Token即可。

Untitled 29.png

3.5.2 登录与登出

// 登录
export const signIn = async (data: { email: string; password: string }) => {
  const { email, password } = data;
  const { data: user, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  });
  if (error) throw new Error(error.message);
  return user;
};

// 退出登录
export const logout = async () => {
  const { error } = await supabase.auth.signOut();
  if (error) throw new Error(error.message);
};

当我们实现用户认证功能后,需要将数据库原本设置为 public 的 policies 更改为仅认证的用户才可进行相关操作,这样保证了数据的安全性。同时,在页面中对特定路由进行权限校验,如果用户未登陆需要自动跳转到登陆页面。

Untitled 30.png

// 判断用户是否登陆,即拿到用户信息
export async function getCurrentUser() {
  const { data: session } = await supabase.auth.getSession();
  if (!session.session) return null;
  
  const { data, error } = await supabase.auth.getUser();
  if (error) throw new Error(error.message);
  return data?.user;
}

3.6 实时订阅

Supabase 提供了一个全球分布式的实时服务器集群,可以支持“以低延迟从客户端向客户端发送临时消息”、“跟踪和同步客户端之间的共享状态”、“侦听 Postgres 数据库更改并将其发送给授权客户端”等。通过 Supabase 提供的 RealTime 能力,我们能够实现非常多实时性的应用,例如实时光标、实时排行榜、聊天工具、共享文本编辑器、共享白板等等。在本项目中,我们将订单列表设置为实时更新,当数据库中的数据发生改变,列表展示的内容自动同步更新。默认情况下,我们创建的数据库表是未启用实时广播的,我们需要将 orders 表启用 RealTime。然后,根据对应的 API 侦听数据库的变化即可。

编组 13.png

// 添加订阅
export const createSubscribe = () => {
  return supabase
    .channel("custom-all-channel")
    .on("postgres_changes", { event: "*", schema: "public", table: "orders" }, (payload) => {
      console.log("Change received!", payload);
    })
    .subscribe();
};

// 取消订阅
export const removeSubscribe = (myChannel: RealtimeChannel) => {
  supabase.removeChannel(myChannel);
};
useEffect(() => {
    const myChannel = createSubscribe();
    return () => removeSubscribe(myChannel);
  }, []);

四、总结

本文为前端开发者提供了一份详尽的 Supabase 使用指南,通过一个商品订单系统示例,详细演示了文件存储、用户认证和实时订阅的内容,项目初始化到增删改查等内容可阅读上篇。本文的示例仅介绍了 Supabse 的基础应用,更多更多内容和功能可查阅官方文档进行进一步探索哦 😐 通过 Supabase 提供的能力,前端能够轻松地实现对数据库增删改查、用户权限管理、文件上传、实时订阅等功能,不再需要后端编写相应的接口来提供给前端使用。在某些场景下,Supabase 扩展了前端的能力,前端能够轻松地跳过与数据库之间的后端瓶颈来独立且轻松地实现一个完整的应用。

参考资料: