10 KiB
如需我在本地使用你的 Supabase 凭证演示一次完整的注册→查询→发送流程,或将持久化切换为仅 Supabase(移除本地 JSON 回退),请直接告诉我你的选择并提供测试凭证或确认权限范围。
故障排查记录(已执行)
-
我们在仓库中运行了两个辅助脚本以排查 Supabase 凭证问题:
server/probe_supa.js:对单个 key 发起 REST 请求并打印响应(用于快速验证)。server/try_supa_keys.js:扫描仓库中形似 JWT 的字符串并逐一尝试对 Supabase REST 发起请求,打印每个 candidate 的 HTTP 状态与响应预览。
-
排查结果摘要:
- 在仓库中发现 6 个看起来像 JWT 的候选 key,均对
GET /rest/v1/push_devices?user_id=eq.<user>返回 HTTP 401(包括PGRST301/Invalid authentication credentials)。 - 说明这些仓库内的字符串不是当前 Supabase 项目可用的
service_rolekey,或 Supabase 项目/Key 已被替换/撤销,或请求的 Supabase URL 与当时不同。
- 在仓库中发现 6 个看起来像 JWT 的候选 key,均对
推荐操作(二选一)
A)使用正确的 Supabase service_role key(推荐)
- 在 Supabase 控制台:Project → Settings → API → Service role key,复制该 key(仅在后端使用,切勿公开)。
- 在服务器启动前注入环境变量并启动:
$env:SUPA_URL='http://192.168.1.62:18000'
$env:SUPA_KEY='(粘贴你的 service_role key)'
node server/push-server.js
或后台运行并记录日志:
$env:SUPA_URL='http://192.168.1.62:18000'
$env:SUPA_KEY='(你的 key)'
Start-Process node -ArgumentList 'server/push-server.js' -RedirectStandardOutput '.\\server.log' -RedirectStandardError '.\\server.err' -PassThru
运行后可检查 server.log(包含 supaFetch 调试输出),并用以下命令验证:
Invoke-RestMethod -Uri 'http://localhost:7301/api/v1/push/devices?user_id=<user-uuid>' -Method GET | ConvertTo-Json -Depth 5
B)绕过 Supabase(仅用于本地快速验证)
如果你只是想立即验证下发链路,可把已知的 device(cid + user_id)写入本地 server/data/push_devices.json,然后执行 mock 推送:
# 查看本地 devices 文件
Get-Content .\server\data\push_devices.json -Raw | ConvertFrom-Json
# 手动追加(示例,替换 cid 与 user_id)
$devs = Get-Content .\server\data\push_devices.json -Raw | ConvertFrom-Json
$devs += @{ cid='d9aa69ec415...'; user_id='a8e3a568-fc1f-4237-bcc5-5722e2fca0a3'; platform='android'; created_at=(Get-Date).ToString('o'); updated_at=(Get-Date).ToString('o'); active=$true }
$devs | ConvertTo-Json -Depth 5 | Set-Content .\server\data\push_devices.json -Encoding utf8
# 然后测试发送(mock)
Invoke-RestMethod -Uri 'http://localhost:7301/api/v1/push/send' -Method POST -ContentType 'application/json' -Body (@{ user_id='a8e3a568-fc1f-4237-bcc5-5722e2fca0a3'; notification=@{ title='测试'; body='hello' } } | ConvertTo-Json)
已添加的辅助脚本
server/probe_supa.js— 对单个 key 发起请求并打印响应(用于快速验证)。server/try_supa_keys.js— 在仓库中查找 JWT 样式字符串并逐一尝试调用 Supabase REST,打印每个 candidate 的状态与响应预览。
如果你把正确的 service_role key 提供给我(仅用于本次会话),我可以代为注入环境、重启服务并把 supaFetch 的调试输出和最终结果贴回给你;或我可以现在把截图中已有的 cid/user_id 写入本地 JSON 并立即做一次 mock 下发测试。
Push Server (开发用)
这是一个用于本地开发与调试的轻量 Node.js 推送后端(mock)。
功能:
- 注册/更新设备:
POST /api/v1/push/register{ cid, user_id, platform } - 注销设备:
POST /api/v1/push/unregister{ cid | user_id } - 列出设备:
GET /api/v1/push/devices?user_id=...&active=true|false - 发送推送(模拟):
POST /api/v1/push/send{ cids:[], user_id, notification, payload }
如果你有真实的推送服务端 API,可以设置环境变量 PUSH_PROXY_URL(和可选的 PUSH_PROXY_TOKEN),服务器会将 /api/v1/push/send 请求代理到该 URL。
快速使用:
cd server
npm install
npm start
默认监听端口:7301,可通过 PORT 环境变量修改。
设备存储在 server/data/push_devices.json,用于本地持久化。
可选:直接写入 Supabase
服务器可以可选地将 push_devices 记录直接写入 Supabase/Postgres(适用于生产或集成测试)。启用方法:在启动前设置下列环境变量:
SUPA_URL— Supabase 项目 URL,例如https://xyzcompany.supabase.coSUPA_KEY— Supabaseservice_rolekey(仅在服务器端使用,切勿暴露给客户端)
当这两个变量存在时,服务会通过 PostgREST REST API 向 /rest/v1/push_devices 发起 upsert(使用 on_conflict=cid),并在注销时将设备的 is_active 标记为 false。同时本地 JSON 存储仍会保留为回退。
示例(PowerShell):
$env:SUPA_URL = 'https://xyz.supabase.co'
$env:SUPA_KEY = 'eyJhbGci...'
npm start
请确保你的 Supabase 项目已经包含与仓库迁移脚本匹配的 push_devices 表:
pages/mall/delivery/doc/需求文档/20260224_add_push_devices_and_notifications.sql。
Supabase 表结构与权限(快速参考)
下面是 push_devices 表的最小字段集合,供你在 Supabase 中快速验证或手动创建:
CREATE TABLE public.push_devices (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NULL,
cid varchar(255) NOT NULL,
platform varchar(32) NOT NULL DEFAULT 'android',
appid varchar(128) NOT NULL DEFAULT 'default',
is_active boolean NOT NULL DEFAULT true,
last_seen_at timestamptz NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_push_devices_appid_cid ON public.push_devices(appid, cid);
权限与安全建议:
- 生产环境请务必只在后端使用
service_role(SUPA_KEY),不要将其暴露给客户端。后端应负责向 Supabase 写入/更新设备记录。 - 如果你需要通过客户端直接调用 Supabase REST(不推荐),请配置 RLS 策略并只允许安全的最小操作。
- 推荐做法:后端使用
service_role写入;客户端只调用后端的/api/v1/push/register。
示例:使用 service_role 通过 PostgREST 插入设备(等同于本服务中执行的请求):
curl -X POST "${SUPA_URL}/rest/v1/push_devices?on_conflict=cid" \
-H "apikey: ${SUPA_KEY}" \
-H "Authorization: Bearer ${SUPA_KEY}" \
-H "Content-Type: application/json" \
-d '[{"cid":"CID_TEST_001","user_id":"<user-uuid>","platform":"android","appid":"default","is_active":true}]'
注意事项:
- 如果你使用的是 Supabase 的
uuid_generate_v4()功能,可能需要在数据库安装uuid-ossp或使用gen_random_uuid()(pgcrypto)。迁移脚本中已包含兼容性处理。 - 本服务对 Supabase 的写入为异步非阻塞:写入失败不会阻止本地响应,但会在日志中记录错误。可根据需要修改为同步错误返回策略。
如需我把本地 JSON 回退移除并只保留 Supabase 持久化(需你确认并提供测试凭证),我可以继续实现并更新代码与文档。
服务说明(快速参考)
服务简介
- 目的:为开发/集成阶段提供一个轻量的推送后端,用于接收客户端上报的推送客户端 ID(CID)、管理设备状态,并在开发中触发/代理推送以验证链路。
- 主要职责:接收设备注册/注销、列出设备、触发推送(mock 或代理到真实推送服务)、可选将设备写入 Supabase。
暴露的接口(HTTP)
GET /health:健康检查POST /api/v1/push/register:注册或更新设备,body:{ cid, user_id, platform, ... }POST /api/v1/push/unregister:注销设备,body:{ cid | user_id }GET /api/v1/push/devices:列出设备,query:user_id,activePOST /api/v1/push/send:发送推送(开发环境为 mock;可代理到PUSH_PROXY_URL)
数据与持久化
- 开发默认将设备保存在本地文件:
server/data/push_devices.json(回退/离线使用)。 - 可选:当设置
SUPA_URL和SUPA_KEY时,服务会通过 Supabase REST(PostgREST)向push_devices表 upsert/patch 同步设备记录(异步、非阻塞)。
重要环境变量
PORT:监听端口(默认 7301)PUSH_PROXY_URL/PUSH_PROXY_TOKEN:将/api/v1/push/send代理到真实推送服务SUPA_URL/SUPA_KEY/SUPA_SCHEMA:启用 Supabase 同步(SUPA_KEY应为服务端service_role,仅服务器端使用)
安全与部署注意
- 切勿将
SUPA_KEY(service_role)暴露给客户端;只能在后端使用。 - 生产场景应:后端持有凭证并负责写入/验证;对客户端使用后端接口,不直接对 Supabase 写入。
- 如直接允许客户端写 Supabase,必须开启 RLS 并最小化权限(一般不推荐)。
表结构与迁移
- 已提供迁移脚本:
pages/mall/delivery/doc/需求文档/20260224_add_push_devices_and_notifications.sql(包含push_devices与express_notifications表及触发器、索引)。
快速测试示例 PowerShell:
Invoke-RestMethod -Uri 'http://localhost:7301/api/v1/push/register' -Method POST -ContentType 'application/json' -Body '{"cid":"CID_TEST_001","user_id":"user-1","platform":"android"}'
curl(示例 upsert 到 Supabase,需替换变量):
curl -X POST "${SUPA_URL}/rest/v1/push_devices?on_conflict=cid" \
-H "apikey: ${SUPA_KEY}" \
-H "Authorization: Bearer ${SUPA_KEY}" \
-H "Content-Type: application/json" \
-d '[{"cid":"CID_TEST_001","user_id":"<user-uuid>","platform":"android","appid":"default","is_active":true}]'
如需我在本地使用你的 Supabase 凭证演示一次完整的注册→查询→发送流程,或将持久化切换为仅 Supabase(移除本地 JSON 回退),请直接告诉我你的选择并提供测试凭证或确认权限范围。