Supabase 实战指南:从0到1搭建全栈后端

文章目录

      • 一、前期准备:账号注册与项目初始化
        • [1.1 注册 Supabase 账号](#1.1 注册 Supabase 账号)
        • [1.2 创建首个 Supabase 项目](#1.2 创建首个 Supabase 项目)
        • [1.3 获取核心访问凭证](#1.3 获取核心访问凭证)
      • 二、核心功能实战:从配置到开发
        • [2.1 数据库配置:创建表与安全策略](#2.1 数据库配置:创建表与安全策略)
        • [2.2 认证系统:实现登录注册功能](#2.2 认证系统:实现登录注册功能)
          • [方式 1:邮箱 / 密码认证(基础版)](#方式 1:邮箱 / 密码认证(基础版))
          • [方式 2:GitHub OAuth 登录(快捷版)](#方式 2:GitHub OAuth 登录(快捷版))
        • [2.3 存储服务:文件上传与访问控制](#2.3 存储服务:文件上传与访问控制)
        • [2.4 实时数据:实现文件列表自动更新](#2.4 实时数据:实现文件列表自动更新)
        • [2.5 边缘函数:文件上传后发送通知](#2.5 边缘函数:文件上传后发送通知)
      • 三、进阶操作:优化与扩展
        • [3.1 开发环境隔离:使用分支功能](#3.1 开发环境隔离:使用分支功能)
        • [3.2 性能优化技巧](#3.2 性能优化技巧)
        • [3.3 安全加固措施](#3.3 安全加固措施)
      • 四、常见问题与排查
        • [4.1 数据无法访问?检查 RLS 策略](#4.1 数据无法访问?检查 RLS 策略)
        • [4.2 实时订阅无响应?检查通道状态](#4.2 实时订阅无响应?检查通道状态)
        • [4.3 文件上传失败?检查存储权限](#4.3 文件上传失败?检查存储权限)

一、前期准备:账号注册与项目初始化

1.1 注册 Supabase 账号

Supabase 支持多种快捷登录方式,推荐使用 GitHub 账号登录(适配开源开发者习惯):

  1. 访问 Supabase 官网,点击右上角 "Sign In"

  2. 选择 "Continue with GitHub",授权 GitHub 账号完成登录

  3. 首次登录需完善基本信息(姓名、邮箱),无需信用卡即可使用免费计划

1.2 创建首个 Supabase 项目
  1. 登录后进入控制台,点击 "New Project" 按钮

  2. 填写项目核心信息:

  • Project Name:如 "file-management-system"(建议与实战项目匹配)

  • Password:设置数据库管理员密码(需牢记,自托管时会用到)

  • Region:选择就近区域(如亚洲用户选 "Singapore",降低延迟)

  • Pricing Plan:默认选择 "Free"(包含 500MB 存储、1GB 数据库,足够原型开发)

  1. 点击 "Create Project",等待 2-3 分钟完成初始化(后台自动部署 Postgres 与配套服务)
1.3 获取核心访问凭证

项目创建后,进入 "Settings"→"API" 页面,记录三个关键信息(前端开发必备):

  • Project URL :API 访问基础地址(如 https://abc123.supabase.co

  • anon public:匿名访问密钥(前端 SDK 初始化用,默认带有限制权限)

  • service_role:管理员密钥(后端 / 函数用,需严格保密,勿暴露在前端)


二、核心功能实战:从配置到开发

以 "文件管理系统" 实战场景为例,详解 Supabase 五大核心功能的使用流程:

2.1 数据库配置:创建表与安全策略

通过 Supabase Studio 可视化操作,无需手写 SQL 即可完成数据层搭建:

  1. 进入 "SQL Editor"→"New Query",使用 AI 助手生成建表语句:
  • 输入自然语言:"创建用户文件表,包含 id、user_id、file_name、file_path、size、created_at 字段"

  • 点击 "Generate SQL",系统自动生成建表语句,点击 "Run" 执行

  1. 配置 行级安全(RLS)(实现 "用户仅访问自己的文件"):
  • 进入 "Authentication"→"Policies",点击 "New Policy"

  • 选择 "For full access"→"Use template",设置规则:

    • 表:user_files

    • 权限:SELECT/INSERT/UPDATE/DELETE

    • 条件:user_id = auth.uid()(自动关联当前登录用户 ID)

  1. 验证配置:进入 "Table Editor",手动插入测试数据(指定 user_id 为某个用户 UUID),切换用户登录后仅能看到自己的数据
2.2 认证系统:实现登录注册功能

基于 JS SDK 快速集成认证模块,支持邮箱 / 密码与 OAuth 两种方式:

方式 1:邮箱 / 密码认证(基础版)
复制代码
// 1. 初始化客户端(全局仅需执行一次)

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(

       import.meta.env.VITE_SUPABASE_URL,  // 从环境变量读取,避免硬编码

       import.meta.env.VITE_SUPABASE_ANON_KEY

)

// 2. 用户注册

const signUp = async (email, password) => {

       const { data, error } = await supabase.auth.signUp({

         email,

         password,

         options: {

           data: {  // 额外存储用户昵称等信息

             username: 'new-user'

           }

         }

       })

       if (error) throw error

       return data.user  // 返回新创建的用户对象

}

// 3. 用户登录

const signIn = async (email, password) => {

       const { data, error } = await supabase.auth.signInWithPassword({

         email,

         password

       })

       if (error) throw error

       return data.session  // 返回包含 JWT 的会话信息

}

// 4. 监听登录状态变化

supabase.auth.onAuthStateChange((event, session) => {

       if (event === 'SIGNED_IN') {

         console.log('用户已登录:', session.user.id)

         // 跳转到文件列表页

       } else if (event === 'SIGNED_OUT') {

         // 清空本地缓存,跳转到登录页

       }

})
方式 2:GitHub OAuth 登录(快捷版)
复制代码
const signInWithGitHub = async () => {

       const { data, error } = await supabase.auth.signInWithOAuth({

         provider: 'github',

         options: {

           redirectTo: 'http://localhost:3000/callback'  // 登录成功后的回调地址

         }

       })

       if (error) throw error

       // 自动跳转至 GitHub 授权页面

}
2.3 存储服务:文件上传与访问控制

基于 S3 兼容的存储服务,实现文件的安全管理:

  1. 先在 Supabase 控制台创建存储桶:
  • 进入 "Storage"→"New Bucket",名称设为 "user-documents"

  • 权限选择 "Private"(仅认证用户可访问)

  • 勾选 "Enable Row Level Security"(与 RLS 联动)

  1. 前端实现文件上传与下载:

    // 1. 上传文件(需用户已登录)

    const uploadFile = async (file) => {

    复制代码
        // 生成唯一文件名,避免重复
    
        const fileName = ${Date.now()}-${file.name}`
    
        // 上传路径格式:桶名/用户ID/文件名
    
        const filePath = `user-documents/${supabase.auth.user().id}/${fileName}`
    
             
    
        const { data, error } = await supabase.storage
    
          .from('user-documents')
    
          .upload(filePath, file, {
    
            cacheControl: '3600',  // 缓存1小时
    
            upsert: false  // 不允许覆盖同名文件
    
          })
    
             
    
        if (error) throw error
    
        // 上传成功后,将文件信息存入数据库
    
        await supabase
    
          .from('user_files')
    
          .insert({
    
            user_id: supabase.auth.user().id,
    
            file_name: file.name,
    
            file_path: data.path,
    
            size: file.size
    
          })
    
        return data

    }

    // 2. 获取文件访问链接(临时签名URL)

    const getFileUrl = async (filePath) => {

    复制代码
        const { data, error } = await supabase.storage
    
          .from('user-documents')
    
          .createSignedUrl(filePath, 3600)  // 1小时有效期
    
             
    
        if (error) throw error
    
        return data.signedUrl  // 用于下载或预览文件

    }

2.4 实时数据:实现文件列表自动更新

借助 WebSocket 服务,无需刷新页面即可同步数据变化:

复制代码
// 订阅当前用户的文件变更

const subscribeToFiles = () => {

       const user = supabase.auth.user()

       if (!user) return

            

       // 创建订阅通道(命名为"user-files"便于管理)

       const channel = supabase.channel('user-files')

            

       // 监听 user_files 表的 INSERT/UPDATE/DELETE 事件

       channel.on(

         'postgres_changes',

         {

           event: '*',  // 监听所有事件

           schema: 'public',

           table: 'user_files',

           filter: `user_id=eq.${user.id}`  // 仅订阅当前用户的数据

         },

         (payload) => {

           // 根据事件类型更新前端列表

           switch (payload.eventType) {

             case 'INSERT':

               addFileToUI(payload.new)  // 添加新文件

               break

             case 'DELETE':

               removeFileFromUI(payload.old.id)  // 删除文件

               break

             case 'UPDATE':

               updateFileInUI(payload.new)  // 更新文件信息

               break

           }

         }

       ).subscribe()  // 启动订阅

            

       // 组件卸载时取消订阅

       return () => supabase.removeChannel(channel)

}
2.5 边缘函数:文件上传后发送通知

创建边缘函数处理异步逻辑,避免前端直接处理复杂业务:

  1. 安装 Supabase CLI(需先安装 Node.js):

    npm install -g supabase

  2. 初始化函数项目并创建函数:

    supabase init # 初始化本地配置

    supabase functions new file-upload-notification # 创建函数

  3. 编写函数逻辑(supabase/functions/file-upload-notification/index.ts):

    import { createClient } from '@supabase/supabase-js'

    // 使用 service_role 密钥初始化(拥有管理员权限)

    const supabase = createClient(

    复制代码
        Deno.env.get('SUPABASE_URL')!,
    
        Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!

    )

    Deno.serve(async (req) => {

    复制代码
        const { filePath, userId } = await req.json()
    
             
    
        // 1. 获取用户邮箱
    
        const { data: user } = await supabase
    
          .from('profiles')
    
          .select('email')
    
          .eq('id', userId)
    
          .single()
    
             
    
        // 2. 发送通知(此处简化为日志,实际可集成邮件服务)
    
        console.log(`通知用户 ${user.email}:文件 ${filePath} 已上传`)
    
             
    
        return new Response(JSON.stringify({ status: 'success' }), { status: 200 })

    })

  4. 部署函数并配置触发:

    supabase functions deploy file-upload-notification # 部署到边缘节点

  • 在控制台进入 "Edge Functions"→"Triggers",添加存储事件触发:

    • 触发源:storage.objects.insert(文件上传时触发)

    • 目标函数:file-upload-notification


三、进阶操作:优化与扩展

3.1 开发环境隔离:使用分支功能

类似 Git 分支,创建独立开发环境避免影响生产数据:

  1. 进入项目控制台→"Project Settings"→"Branches"

  2. 点击 "Create Branch",命名为 "dev"

  3. 开发环境使用分支的 URL 与密钥,测试完成后通过 "Merge" 合并到主分支

3.2 性能优化技巧
  • 数据库索引 :在 user_files.user_iduser_files.created_at 字段创建索引,加速查询

  • API 缓存 :对静态数据(如文件分类)启用缓存,设置 cacheControl: 'public, max-age=86400'

  • 批量操作 :使用 insert([...items]) 替代循环单个插入,减少 API 调用次数

3.3 安全加固措施
  • 密钥管理 :前端仅使用 anon public 密钥,service_role 仅在边缘函数或后端使用

  • 存储策略 :为存储桶添加访问策略,限制用户仅能访问自己路径下的文件(storage.foldername() = auth.uid()

  • SQL 防护 :禁用公共 schema 的 ALTER TABLE 权限,防止恶意修改表结构


四、常见问题与排查

4.1 数据无法访问?检查 RLS 策略
  • 现象:调用 select 接口返回空数组,但表中存在数据

  • 排查:进入 "Table Editor"→"Policies",确认策略是否生效,可临时关闭 RLS 测试(生产环境禁用此操作)

4.2 实时订阅无响应?检查通道状态
  • 现象:数据变更后前端未收到通知

  • 排查:

  1. 确认用户已登录(匿名用户可能无订阅权限)

  2. 检查过滤条件是否正确(如 user_id 拼写错误)

  3. 调用 channel.getStatus() 查看订阅状态是否为 "SUBSCRIBED"

4.3 文件上传失败?检查存储权限
  • 现象:上传返回 "403 Forbidden"

  • 排查:

  1. 确认存储桶权限为 "Private" 而非 "Public"

  2. 检查上传路径是否符合策略要求(如是否包含用户 ID)

  3. 查看控制台 "Storage"→"Logs" 获取详细错误信息

相关推荐
观望过往2 天前
Supabase 适用场景全解析:从原型到生产的落地指南
supabase
西京刀客1 个月前
AI时代BaaS | 开源的后端即服务(BaaS)平台Supaba
baas·supabase
WEB前端圈1 年前
在postman中调试supabase的API接口
测试工具·lua·postman·supabase
若苗瞬1 年前
使用 Supabase 的 Realtime + Storage 非常方便呢
supabase·realtime·bucket
若苗瞬2 年前
用 Supabase CLI 进行本地开发环境搭建
cli·scoop·wsl2·supabase