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>
相关推荐
IT小哥哥呀3 小时前
电池制造行业数字化实施
大数据·制造·智能制造·数字化·mom·电池·信息化
Xi xi xi3 小时前
苏州唯理科技近期也正式发布了国内首款神经腕带产品
大数据·人工智能·经验分享·科技
yumgpkpm3 小时前
华为鲲鹏 Aarch64 环境下多 Oracle 、mysql数据库汇聚到Cloudera CDP7.3操作指南
大数据·数据库·mysql·华为·oracle·kafka·cloudera
UMI赋能企业4 小时前
制造业流程自动化提升生产力的全面分析
大数据·人工智能
TDengine (老段)5 小时前
TDengine 数学函数 FLOOR 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
派可数据BI可视化7 小时前
商业智能BI 浅谈数据孤岛和数据分析的发展
大数据·数据库·数据仓库·信息可视化·数据挖掘·数据分析
jiedaodezhuti7 小时前
Flink性能调优基石:资源配置与内存优化实践
大数据·flink
Lx3529 小时前
Flink窗口机制详解:如何处理无界数据流
大数据
Lx3529 小时前
深入理解Flink的流处理模型
大数据
Lx3529 小时前
Flink vs Spark Streaming:谁更适合你的实时处理需求?
大数据