954 字
5 分钟
使用 Next.js 和 Supabase 进行全栈开发:构建现代博客系统

什么是 Supabase?#

Supabase 被誉为“开源版的 Firebase”。它不仅仅是一个数据库,而是一个高度集成的后端服务套件。其核心架构基于坚如磐石的 PostgreSQL,并在此基础上提供了开发者最急需的几种能力:

  • PostgreSQL 数据库:完整的 SQL 支持,非 NoSQL。
  • 用户认证 (Auth):内置 OAuth、魔术链接及传统的账号密码登录。
  • 实时功能 (Realtime):监听数据库变更并同步至前端。
  • 文件存储 (Storage):轻松托管图片、视频等媒体文件。
  • 边缘函数 (Edge Functions):全球分布的无服务器代码执行环境。

核心优势:为什么不再选择 Firebase?#

  1. 无供应商锁定:基于开源技术,你可以随时将其迁移到自己的服务器。
  2. 关系型力量:利用复杂的 SQL 查询、外键关系和事务,这在 NoSQL(如 Firestore)中很难处理。
  3. RLS(行级安全):直接在数据库层面处理权限控制,前端 API 调用更加安全、简洁。

步骤一:环境搭建与依赖安装#

1. 创建 Next.js 应用#

Terminal window
npx create-next-app@latest next-supabase-blog --tailwind
cd next-supabase-blog

2. 安装 Supabase 客户端及工具#

注意:我们现在通常使用更精简的 @supabase/auth-helpers-nextjs 来处理 Next.js 的服务端渲染(SSR)认证。

Terminal window
npm install @supabase/supabase-js react-simplemde-editor react-markdown uuid

步骤二:数据库建模与安全策略 (RLS)#

在 Supabase 控制台的 SQL Editor 中运行以下脚本。这里定义了博客表结构,并启用了 Row Level Security,这是 Supabase 安全的核心。

-- 创建帖子表
CREATE TABLE posts (
id uuid DEFAULT uuid_generate_v4() primary key,
user_id uuid references auth.users not null,
title text not null,
content text not null,
inserted_at timestamp with time zone default now() not null
);
-- 开启行级安全
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- 策略 1:允许所有人查看帖子(公共访问)
CREATE POLICY "Public access to posts" ON posts FOR SELECT USING (true);
-- 策略 2:仅允许认证用户创建帖子
CREATE POLICY "Authenticated users can insert" ON posts FOR INSERT WITH CHECK (auth.uid() = user_id);
-- 策略 3:仅允许作者本人修改/删除
CREATE POLICY "Authors can update their own posts" ON posts FOR UPDATE USING (auth.uid() = user_id);

步骤三:初始化 Supabase 客户端#

在项目根目录创建 .env.local,填入你的凭证:

NEXT_PUBLIC_SUPABASE_URL=你的项目地址
NEXT_PUBLIC_SUPABASE_ANON_KEY=你的匿名Key

创建 lib/supabaseClient.js

import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
);

步骤四:实现用户状态监听#

pages/_app.js(或根布局组件)中,我们需要监听用户的登录状态,以便实时更新 UI。

import { useState, useEffect } from 'react';
import { supabase } from '../lib/supabaseClient';
function MyApp({ Component, pageProps }) {
const [session, setSession] = useState(null);
useEffect(() => {
// 获取当前会话
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
});
// 监听状态变更(登录/退出)
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});
return () => subscription.unsubscribe();
}, []);
return <Component {...pageProps} session={session} />;
}

步骤五:创建帖子(客户端 CRUD)#

pages/create-post.js 中,我们使用 Supabase 的 from().insert() 方法。

async function createNewPost() {
if (!title || !content) return;
// 在新版 SDK 中,应先获取当前用户
const { data: { user } } = await supabase.auth.getUser();
const { error } = await supabase
.from('posts')
.insert([{
title,
content,
user_id: user.id
}]);
if (error) {
console.error('创建失败:', error.message);
} else {
router.push('/');
}
}

最佳实践与避坑指南#

  1. 异步获取用户:永远不要依赖本地缓存的用户对象。在执行写入操作前,始终调用 await supabase.auth.getUser() 以确保会话有效且未被篡改。
  2. 环境变量命名:在 Next.js 中,任何需要在客户端访问的环境变量必须以 NEXT_PUBLIC_ 开头。
  3. RLS 必开:如果你忘记开启 RLS,任何知道你 API Key 的人都可以通过控制台删除你的整个数据库。

总结#

结合 Next.js 的高效渲染和 Supabase 的全能后端,开发者可以在不到一小时内搭建起一个具备生产级安全性的应用。

使用 Next.js 和 Supabase 进行全栈开发:构建现代博客系统
https://sw.rscclub.website/posts/nextsup/
作者
杨月昌
发布于
2022-03-18
许可协议
CC BY-NC-SA 4.0