离线推送排障

“推送没收到”在本项目里有三种完全不同的原因:设备 token 没注册、厂商通道没有真实发送能力、离线 webhook 没被应用接住。本页按投递状态机逐层排查,避免把 sent=0 误判成“服务端坏了”。

能力边界(先读)

厂商通道(APNs/FCM/华为/小米/OPPO/vivo)当前只存储与校验配置,不发起真实发送;投递尝试只会写入 no_token 或 not_configured,sent 恒为 0。

真正的“离线通知”链路是:接收方无在线 WS 会话 → 服务端 POST 到应用配置的 webhookUrl(3 秒超时、无签名、无重试)→ 应用自己调厂商推送。

通知点击跳转、角标、通知分组、多语言推送模板均未实现。

投递状态机​

状态含义当前实现会写入吗下一步
no_token该用户没有 active 设备 token会客户端注册 token;确认用户未注销/封禁
not_configured有 token,但厂商适配器未配置/未实现会(终态)这是预期结果;改用 webhook 链路或等待真实适配器
queued已入队待发送预留—
sent厂商已接受预留(恒 0)当前不可能出现
failed厂商明确失败预留真实适配器接入后才可能

排查步骤​

  1. 先确认 token 是否存在

    管理端查询 GET /api/admin/apps/{appkey}/push/tokens?userId=…;客户端也可查本人 token。每用户活跃 token 上限 20 个。

  2. 再看投递记录状态

    创建投递后查列表或单条:no_token 是设备问题,not_configured 是能力问题(预期)。

  3. 确认 webhook 是否配置且可达

    回调/推送 webhook 地址、HTTPS、接收端 2xx;服务端 3 秒超时、无签名、无重试,失败不会补发。

  4. 核对服务开通与用户状态

    推送相关服务未开通返回 1021;注销/封禁用户 1016。

  5. 最后才看厂商侧

    本项目不代发厂商推送;如果 webhook 已收到,问题在应用自己的厂商 SDK/凭据/证书。

JavaScript
import { AdminClient } from '@ni-paas-im/server-sdk';

const admin = new AdminClient({ baseUrl: 'http://127.0.0.1:8080', adminSecret: process.env.IM_ADMIN_SECRET });

// 1) 查设备 token
const tokens = await admin.request('GET', '/apps/demo/push/tokens?userId=alice');
console.log(tokens.items.map((t) => ({ platform: t.platform, active: t.active })));

// 2) 创建投递(≤100 用户;title 1–128 字符、body 1–2048)
const created = await admin.createPushDeliveries({
  appkey: 'demo',
  userIds: ['alice'],
  title: '订单提醒',
  body: '你的订单已发货',
});
console.log(created.sent, created.deliveries[0].status); // 0 'no_token' | 'not_configured'

// 3) 仅 failed / not_configured 可重试;no_token 需先补设备 token
if (created.deliveries[0].status === 'not_configured') {
  await admin.retryPushDelivery({ appkey: 'demo', deliveryId: created.deliveries[0].deliveryId });
}

// 4) 统计口径:deliveryCounts 来自服务端尝试记录;sent 只可能由未来真实适配器写入
const stats = await admin.getPushStats({ appkey: 'demo' });

客户端注册 token​

// Web/Electron SDK 已提供 token 方法;其它端可直接调客户端 REST
await client.registerPushToken({
  platform: 'web',
  token: await getVendorToken(), // 由宿主集成厂商 SDK 后取得
  deviceId: 'browser-uuid',
  appVersion: '2.0.0',
});
const mine = await client.getPushTokens();
await client.unregisterPushToken(mine.data[0].tokenId);
curl -sS -X POST "http://127.0.0.1:8080/api/apps/demo/push/tokens" \
  -H "authorization: Bearer $USER_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"token":"vendor-device-token-abc","platform":"android","deviceId":"pixel-7","appVersion":"2.0.0"}'
字段 / 规则值失败表现
platformios / android / web / huawei / xiaomi / oppo / vivo / fcm未知平台 1001
token8–512 字符(trim 后)长度非法 1001
每用户活跃上限20 个超限 1001
设备换绑同一 (platform, token) 被其他用户注册 → 旧记录 active=false响应含 reboundFrom
注销/封禁用户不允许注册 token1016

webhook 链路自检​

Shell
# 1) 配置 webhook(控制台或 Admin API)
curl -sS -X POST "http://127.0.0.1:8080/api/admin/apps/demo/push/channels" \
  -H 'X-Admin-Secret: dev-admin' -H 'content-type: application/json' \
  -d '{"channel":"apns","enabled":true,"fields":{"keyId":"ABC123","teamId":"TEAM123","bundleId":"com.example.app","privateKey":"-----BEGIN PRIVATE KEY-----..."}}'

# 2) 通道测试:明确返回未实现,不伪造成功
curl -sS -X POST "http://127.0.0.1:8080/api/admin/apps/demo/push/channels/apns/test" -H 'X-Admin-Secret: dev-admin'

# 3) 让接收者离线后发一条消息,观察你的 webhook 接收器是否收到 POST(3 秒超时、无重试)

常见问题​

为什么 sent 永远是 0?​

厂商真实发送未实现;sent 只可能由真实适配器写入。用 webhook 链路或等待能力发布。

not_configured 需要修吗?​

不需要:它表示“有 token 但适配器未实现/未配置”,是当前预期状态。

no_token 怎么修?​

客户端注册设备 token;确认用户未注销/封禁;检查是否超过每用户 20 个上限。

webhook 没收到离线通知?​

确认接收方确实无在线 WS 会话、webhookUrl 已配置且返回 2xx;该链路无重试,失败即丢。

能只给某个设备推吗?​

投递按用户维度,不能选择具体 token;多设备会各自尝试。

点击通知能跳转吗?​

未实现;webhook 载荷由应用自行决定跳转逻辑。

相关页面​