Supabase实战指南:用开源BaaS构建现代全栈应用

Supabase是Firebase的开源替代方案,基于PostgreSQL构建,提供了数据库、认证、实时订阅、存储和Edge Functions等完整的后端服务。

快速开始

bash
npx create-next-app@latest my-blog --typescript --tailwind
cd my-blog
npm install @supabase/supabase-js @supabase/ssr

数据库与Row Level Security

RLS是Supabase安全模型的核心。通过PostgreSQL策略,在数据库层面控制数据访问:

sql
-- 创建posts表
CREATE TABLE posts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  author_id UUID REFERENCES auth.users(id),
  created_at TIMESTAMPTZ DEFAULT now(),
  published BOOLEAN DEFAULT false
);

-- 启用RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- 所有人可以读已发布的文章
CREATE POLICY "Public can read published posts"
ON posts FOR SELECT
USING (published = true);

-- 作者可以管理自己的文章
CREATE POLICY "Authors manage own posts"
ON posts FOR ALL
USING (auth.uid() = author_id)
WITH CHECK (auth.uid() = author_id);

认证系统

typescript
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr';

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
}

// components/LoginForm.tsx
'use client';

import { createClient } from '@/lib/supabase/client';

export function LoginForm() {
  const supabase = createClient();

  async function signInWithGithub() {
    await supabase.auth.signInWithOAuth({
      provider: 'github',
      options: { redirectTo: `${location.origin}/auth/callback` },
    });
  }

  async function signInWithMagicLink(email: string) {
    const { error } = await supabase.auth.signInWithOtp({
      email,
      options: { emailRedirectTo: `${location.origin}/auth/callback` },
    });
  }

  return (
    <div>
      <button onClick={signInWithGithub}>GitHub登录</button>
      <MagicLinkForm onSubmit={signInWithMagicLink} />
    </div>
  );
}

实时订阅

typescript
// 订阅posts表的实时变化
const supabase = createClient();

const channel = supabase
  .channel('posts-changes')
  .on(
    'postgres_changes',
    { event: '*', schema: 'public', table: 'posts' },
    (payload) => {
      console.log('Change received:', payload.eventType);
      console.log('New data:', payload.new);
    }
  )
  .subscribe();

// 组件卸载时取消订阅
// channel.unsubscribe();

文件存储

typescript
// 上传头像
async function uploadAvatar(userId: string, file: File) {
  const supabase = createClient();

  const fileExt = file.name.split('.').pop();
  const filePath = `${userId}/avatar.${fileExt}`;

  const { data, error } = await supabase.storage
    .from('avatars')
    .upload(filePath, file, { upsert: true });

  if (error) throw error;

  // 获取公开URL
  const { data: { publicUrl } } = supabase.storage
    .from('avatars')
    .getPublicUrl(filePath);

  return publicUrl;
}

实战:文章搜索

typescript
// app/api/search/route.ts
import { createClient } from '@/lib/supabase/server';
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const query = request.nextUrl.searchParams.get('q');
  if (!query) return Response.json({ error: 'Missing query' }, { status: 400 });

  const supabase = await createClient();

  const { data, error } = await supabase
    .from('posts')
    .select('id, title, slug, excerpt')
    .eq('published', true)
    .or(`title.ilike.%${query}%,content.ilike.%${query}%`)
    .order('created_at', { ascending: false })
    .limit(20);

  return Response.json({ data });
}

Edge Functions

typescript
// supabase/functions/send-welcome-email/index.ts
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

Deno.serve(async (req) => {
  const { user } = await req.json();

  // 发送欢迎邮件
  await fetch('https://api.resend.com/emails', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${Deno.env.get('RESEND_API_KEY')}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      from: 'noreply@myapp.com',
      to: user.email,
      subject: '欢迎加入!',
      html: '<h1>欢迎!</h1><p>感谢注册。</p>',
    }),
  });

  return new Response(JSON.stringify({ success: true }), {
    headers: { 'Content-Type': 'application/json' },
  });
});

总结

Supabase提供了生产级的后端基础设施,开源且自托管友好。其核心优势:

  1. PostgreSQL — 世界上最先进的开源数据库
  2. RLS — 数据库级别的安全策略
  3. 实时 — 原生WebSocket支持
  4. 开源 — 无供应商锁定,可自托管
  5. 开发者体验 — 自动生成API,优秀的SDK