supabase 实现聊天板(Chat Board)

supabase 实现聊天板(Chat Board)

前提条件:windows中部署supabase与测试

1) 初始化数据库(在 Studio 中运行 SQL)

在 Studio -> SQL 编辑器 中执行 dev/data.sql 里新增的聊天表与策略,或复制如下片段:

sql 复制代码
-- Messages 表和策略(已包含在 dev/data.sql)
create table if not exists public.messages (
  id bigserial primary key,
  room text not null default 'public',
  username text not null default '匿名',
  content text not null check (char_length(content) > 0),
  created_at timestamptz not null default now()
);

alter table public.messages enable row level security;

drop policy if exists "Anyone can read messages" on public.messages;
create policy "Anyone can read messages"
  on public.messages for select using (true);

drop policy if exists "Anyone can send messages" on public.messages;
create policy "Anyone can send messages"
  on public.messages for insert with check (true);

drop policy if exists "Admins can update messages" on public.messages;
create policy "Admins can update messages"
  on public.messages for update to service_role using (true);

drop policy if exists "Admins can delete messages" on public.messages;
create policy "Admins can delete messages"
  on public.messages for delete to service_role using (true);

alter publication supabase_realtime add table public.messages;

2) 快速测试(REST + Realtime)

  • 环境变量设置

    bash 复制代码
    $env:ANON_KEY = ""
    $env:KONG_HTTP_PORT = "8000"
  • 拉取最近消息:

    bash 复制代码
    curl.exe -H "apikey: $env:ANON_KEY" -H "Authorization: Bearer $env:ANON_KEY" "http://localhost:$env:KONG_HTTP_PORT/rest/v1/messages?select=*&order=created_at.desc&limit=50"
  • 发送消息:

    bash 复制代码
      curl.exe -X POST `
      -H "Content-Type: application/json" `
      -H "apikey: $env:ANON_KEY" `
      -H "Authorization: Bearer $env:ANON_KEY" `
      -d '{\"room\":\"public\",\"username\":\"张三\",\"content\":\"大家好!\"}' `
      "http://localhost:$($env:KONG_HTTP_PORT)/rest/v1/messages"

3) 最小前端片段(可直接嵌入)

将下列 HTML 保存为 chat.html 并在浏览器中打开(注意将 SUPABASE_URLANON_KEY 替换成你的值):

html 复制代码
<!doctype html>
<meta charset="utf-8" />
<title>Chat Board</title>
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
<style>
  body { font-family: sans-serif; max-width: 720px; margin: 24px auto; }
  #messages { border: 1px solid #ddd; padding: 12px; height: 360px; overflow: auto; }
  #form { display: flex; gap: 8px; margin-top: 12px; }
  input, button { padding: 8px; }
  .row { margin: 6px 0; }
  .time { color: #888; font-size: 12px; margin-left: 8px; }
  .user { font-weight: bold; }
  .content { margin-left: 6px; }
  header { display: flex; justify-content: space-between; align-items: center; }
  select { padding: 4px; }
</style>
<header>
  <h1>Chat Board</h1>
  <label>Room:
    <select id="room">
      <option value="public">public</option>
      <option value="random">random</option>
    </select>
  </label>
  <label>User: <input id="username" value="匿名" /></label>
</header>
<div id="messages"></div>
<div id="form">
  <input id="input" placeholder="输入消息..." />
  <button id="send">发送</button>
  <button id="refresh">刷新</button>
  <button id="clear">清屏</button>
  <span id="status"></span>
  </div>
<script>
  const SUPABASE_URL = 'http://localhost:8000';
  const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE';
  const sb = supabase.createClient(SUPABASE_URL, ANON_KEY);

  const $ = (id) => document.getElementById(id);
  const box = $('messages');
  const roomSel = $('room');
  const usernameInput = $('username');
  const status = $('status');
  let channel;

  const isAscii = (s) => /^[\x00-\x7F]+$/.test(s);
  function validateConfig() {
    if (!SUPABASE_URL || !ANON_KEY) {
      status.textContent = '配置缺失:请设置 SUPABASE_URL 和 ANON_KEY';
      return false;
    }
    if (!isAscii(ANON_KEY) || /替换为/.test(ANON_KEY)) {
      status.textContent = '配置错误:请替换为实际 ANON_KEY(ASCII)';
      alert('请将 ANON_KEY 替换为实际匿名密钥字符串(ASCII),否则请求会失败。');
      return false;
    }
    return true;
  }

  function row({ username, content, created_at }) {
    const div = document.createElement('div');
    div.className = 'row';
    const time = new Date(created_at).toLocaleString();
    div.innerHTML = `<span class="user">${username}</span><span class="content">${content}</span><span class="time">${time}</span>`;
    return div;
  }

  async function list() {
    status.textContent = '加载中...';
    const { data, error } = await sb
      .from('messages')
      .select('*')
      .eq('room', roomSel.value)
      .order('created_at', { descending: false })
      .limit(200);
    status.textContent = error ? '加载失败' : `加载 ${data?.length ?? 0} 条`;
    box.innerHTML = '';
    (data || []).forEach(m => box.appendChild(row(m)));
    box.scrollTop = box.scrollHeight;
  }

  async function send() {
    const content = $('input').value.trim();
    if (!content) return;
    const username = usernameInput.value.trim() || '匿名';
    const { error } = await sb.from('messages').insert({ room: roomSel.value, username, content });
    if (error) alert('发送失败: ' + error.message);
    $('input').value = '';
  }

  function subscribe() {
    if (channel) sb.removeChannel(channel);
    channel = sb.channel(`room:${roomSel.value}`)
      .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages', filter: `room=eq.${roomSel.value}` }, payload => {
        box.appendChild(row(payload.new));
        box.scrollTop = box.scrollHeight;
      })
      .subscribe((status) => console.log('subscribe', status));
  }

  $('send').onclick = send;
  $('refresh').onclick = list;
  $('clear').onclick = () => (box.innerHTML = '');
  roomSel.onchange = () => { list(); subscribe(); };

  (async () => { if (!validateConfig()) return; await list(); subscribe(); })();
  </script>
相关推荐
招财小梗16 分钟前
AI矩阵获客,品牌连锁落地有啥方案?
大数据·人工智能·矩阵
黎子越34 分钟前
大模型基础名词概念
大数据
zandy101141 分钟前
主流 AI Agent搜索Skill推荐及高阶选型指南
大数据·人工智能
跨境卫士苏苏1 小时前
2026年做跨境电商,TikTok美区半托管这3个品类正在严查,第2个很多新手还在铺货
大数据·人工智能·跨境电商·营销策略
GIS数据转换器1 小时前
村镇无人机物流配送与跨域监测一体化平台
大数据·运维·人工智能·科技·无人机
知识燃料2 小时前
企业技术决策者落地 AI Agent 体系,AWS 中国峰会有哪些战略与工程内容可看?
大数据·人工智能
TDengine (老段)2 小时前
TDengine 第三方工具 — Telegraf、Kafka Connect、Flink、Spark
大数据·数据库·物联网·flink·kafka·时序数据库·tdengine
guwentian10 小时前
Git Worktree 实战:用并行多 Agent 把开发提速 N 倍
大数据·git·elasticsearch·wroktree
2503_9317124813 小时前
OpenInsight领衔:企业AI数据分析平台(Data Agent/智能问数/智能数据报告)
大数据
朴马丁13 小时前
国际与国产PLM在精细化工赛道的布局:2026年主要厂商技术特色
大数据·运维·人工智能·流程行业plm·化工新材料