**Push Server - 使用与变更说明** 简要说明 - 该文档记录对 `server/push-server.js` 的修改、运行所需的环境变量、表结构依赖、以及如何把 Supabase 的 cid 与通知通过 dCloud UNI‑PUSH 下发的端到端操作步骤。 变更要点(代码修改摘要) - supaFetch: 默认仅发送 `apikey`;仅当 `SUPA_USE_BEARER=true` 或 `SUPA_KEY` 看起来像 JWT(包含两处 ".")时,才发送 `Authorization: Bearer`。避免把明文 service key 当作 JWT 发出导致 PostgREST 拒绝。 - 新增 endpoint `/api/v1/notifications`:将通知写入 `express_notifications`,根据 `aud` 与 `recipient_id` 查询 `push_devices`,再发送推送(proxy 或 mock),并写回通知状态。 - 新增 uni-push adapter `sendToUniPush(targets, notification, payload)`:当设置了 `UNI_PUSH_URL` 时,`/api/v1/push/send` 与 `/api/v1/notifications` 会调用该适配器优先发送到 UNI‑PUSH;否则若设置了 `PUSH_PROXY_URL` 则转发到该 URL。 新增/修改的接口(简要) - GET `/health` — 健康检查。 - POST `/api/v1/push/register` — 注册/更新设备;会写本地 `server/data/push_devices.json`,并尝试 upsert 到 Supabase `push_devices` 表(如果配置了 SUPA_URL + SERVICE_ROLE_KEY)。 - POST `/api/v1/push/unregister` — 注销设备(本地并尝试同步 Supabase)。 - GET `/api/v1/push/devices` — 列出设备(优先从 Supabase 获取)。 - POST `/api/v1/push/send` — 直接按 `cids` 或 `user_id` 发送推送;若 `UNI_PUSH_URL` 存在使用 adapter,否则若 `PUSH_PROXY_URL` 存在转发,默认 mock 返回。 - POST `/api/v1/notifications` — 将通知写入 `express_notifications` 并基于 `aud`/`recipient_id` 拉取 `push_devices` 发推送,成功/失败状态写回 `express_notifications.status_code`。 依赖的数据库表(必须存在) - `public.push_devices`:用于存储设备 cid、user_id/merchant_id、is_active 等(见仓库迁移脚本 `20260224_add_push_devices_and_notifications.sql`)。 - `public.express_notifications`:用于保存通知记录与状态(见迁移脚本)。 关键环境变量(示例与说明) - SUPA_URL — Supabase REST(PostgREST)地址(内部建议 `http://rest:3000`)。 - SERVICE_ROLE_KEY 或 SUPA_KEY — 用作 `apikey` 向 PostgREST 请求(不要把明文放到 Authorization 除非该值确为 JWT)。 - SUPA_USE_BEARER — (可选) 若为 `true` 则强制发送 Authorization: Bearer 。 - UNI_PUSH_URL — (可选) 若设置则使用内置 `sendToUniPush` adapter 直接调用 dCloud uni-push 接口。 - UNI_PUSH_APPID / UNI_PUSH_SECRET — adapter 用于构造或鉴权(按你现有 uni-push 接口调整)。 - PUSH_PROXY_URL / PUSH_PROXY_TOKEN — 若不使用 adapter,可把此设置为你现有的推送代理 URL 与 token,后端会将 {targets, notification, payload} 转发过去。 - PUSH_PROXY_URL 优先级低于 UNI_PUSH_URL:若 UNI_PUSH_URL 存在,优先使用本地 adapter。 运行与测试(本地示例) 1) 安装依赖并启动: ```bash cd server npm install express body-parser cors node-fetch SUPA_URL='http://rest:3000' SERVICE_ROLE_KEY='PASTE_SERVICE_ROLE_KEY' node push-server.js ``` 2) 健康检查: ```bash curl http://localhost:7301/health # 返回 {"ok":true} ``` 3) 注册设备(后端会写本地并尝试写 Supabase): ```bash curl -X POST http://localhost:7301/api/v1/push/register \ -H 'Content-Type: application/json' \ -d '{"cid":"test-cid-1","user_id":"","platform":"android"}' ``` 4) 按 user 发通知(写入 express_notifications 并触发推送): ```bash curl -X POST http://localhost:7301/api/v1/notifications \ -H 'Content-Type: application/json' \ -d '{"aud":"user","recipient_id":"","notification":{"title":"测试","body":"uni-push 测试"}}' ``` 5) 直接按 cid 发(跳过 DB): ```bash curl -X POST http://localhost:7301/api/v1/push/send \ -H 'Content-Type: application/json' \ -d '{"cids":["test-cid-1"],"notification":{"title":"hi","body":"msg"}}' ``` UNI‑PUSH 集成注意事项 - adapter 当前构造 body 使用 `cidList` 与 `message:{title,content,payload}`。请根据你已经验证成功的 uni-push curl 请求体调整字段名与鉴权 header(可使用 `UNI_PUSH_APPID`、`UNI_PUSH_SECRET`、或 `PUSH_PROXY_TOKEN`)。 - 建议:把你成功的 uni-push curl 发给我,我可以把 adapter 的 body/header 精确改成一致格式。 故障与排查要点 - 如果 Supabase 报 401 或 PGRST301:不要把明文 service key 作为 Bearer;使用 `apikey` header,或生成并使用与 `PGRST_JWT_SECRET` 匹配的 JWT。可通过 `docker inspect` 检查容器 env 中的 `PGRST_JWT_SECRET`。 - 如果 `/rest/v1/push_devices` 返回 404:确认表名在 `public` schema 中并加载,或调整请求前缀。 - 查看 push-server 控制台输出中的 `supaFetch` warn 和 proxy 响应体以获取具体错误信息。 后续建议(可选实现) - 将 `express_notifications` 增加 `attempts`、`error`、`sent_at` 字段以支持重试与错误记录;可实现后台 worker 或 pg_notify+listener 做可靠投递与重试。 - 为 `/api/v1/push/send` 与 `/api/v1/notifications` 添加管理员鉴权(例如 `PUSH_ADMIN_KEY`)以限制谁能发送通知。 文件位置 - 文档:[server/PUSH_SERVER_README.md](server/PUSH_SERVER_README.md) - 代码:[server/push-server.js](server/push-server.js) 如果需要,我可以: - 把 adapter 的请求体精确匹配你现有成功的 uni-push curl(请把 curl 发来);或 - 为通知添加重试/记录字段并实现简单重试机制。