在私有化运维、监控告警和自动化脚本等场景中,一个高可靠、低延时、全端覆盖的通知网关至关重要。本项目打造了一套基于 Next.js + Cloudflare + Supabase 的服务端,搭配 Android 14 强保活客户端Windows / PWA 离线推送系统,实现了零漏报、秒级到达的全端告警网关。


🛠️ 一、 核心架构与实现过程

整个网关系统的消息流转路径如下:

[监控脚本 / 业务系统 / Webhook]
             │
             ▼  HTTP POST /api/send (携带标题, 级别, 正文, 截图, TTL)
    ┌─────────────────────────────────────────┐
    │          Next.js 核心处理网关            │
    ├──────────────────┬──────────────────────┤
    │  Supabase 数据库  │  Cloudflare R2 图床  │
    └────────┬─────────┴──────────┬───────────┘
             │                    │
   ┌─────────┴─────────┐        ┌─┴────────────────────────┐
   │ SSE 实时长连接广播 │        │ WebPush (VAPID / WNS)   │
   └─────────┬─────────┘        └─┬────────────────────────┘
             │                    │
             ▼                    ▼
  【Android 客户端】          【PC / Windows 桌面端】
  - 前台服务 (RemoteMessaging) - Service Worker 离线守护
  - 15s 智能探针兜底           - Windows Toast 原生弹窗
  - 四级震动音效提醒           - 任务栏 Badge / 呼吸 Favicon

1. 客户端双引擎连接与强保活机制 (Android 篇)

  • 前台服务保活 (Foreground Service): 深度适配 Android 14(API 34),声明 FOREGROUND_SERVICE_REMOTE_MESSAGING 前台服务类型,配以低干扰系统的驻留通知,结合 BOOT_COMPLETED 开机广播与 AlarmManager 15分钟 Watchdog 守候,防止被系统杀后台。
  • 双引擎收发模式 (SSE + 探针)
    • 引擎 A (SSE 实时流):基于 OkHttp SSE,设置 20s 心跳对齐 Cloudflare Serverless 环境,遇断连后 1s 无感重连。
    • 引擎 B (15s 智能探针):后台 Timer 兜底轮询,若 SSE 因网络切换中断,探针自动抓取未读积压,实现 100% 消息零丢失
  • LRU 幂等去重 (Deduplication): 内部维护容量为 300 的线程安全 LRU 内存集合(processedIds),消除双引擎重复拉取与客户端/服务端时钟不同步带来的问题。
  • 四级提醒引擎: 为 INFOWARNINGERRORCRITICAL 创建独立的系统 NotificationChannel,分别匹配不同的优先级、音效与脉冲震动频率(如 CRITICAL 触发持续强震动与 Heads-up 横幅弹窗)。

2. Windows / PWA 无感离线推送机制 (Web/PC 篇)

  • 微软 WNS 免墙直连: 基于标准的 VAPID (EC P-256) 协议,配合 WebPush 标准。在 Microsoft Edge 浏览器下直连微软 WNS 推送通道,无需翻墙即可实现完全关掉网页后的桌面右下角秒级弹窗
  • Service Worker 离线守护: 在 sw.js 中监听 push 事件,解析 level 级与交互动作 (actions),调用系统原生通知 API,并同步更新桌面 PWA 图标角标 (setAppBadge)。
  • 动态 Canvas 呼吸灯 Favicon: 当网页开启且有未读消息时,使用 HTML5 Canvas 动态绘制带有爆亮外光晕的红点,并以 500ms 周期切换明暗(呼吸灯),穿透浏览器 Icon 强缓存。
  • PowerShell 原生 Toast 兜底: 通过预注册的 Windows PowerShell AUMID({1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}...),支持在 Windows 本地环境下直接调用 PowerShell 触发系统原生 Toast 通知。

📜 二、 核心脚本解析与作用

整个项目由 服务端/Web端 (notify)Android 端 (NotifyGateway) 两个子项目组成。以下是各核心文件的功能解析:

1. 服务端与 Web 端 (notify) 关键脚本作用

脚本文件路径 核心作用与实现逻辑
app/api/send/route.ts 核心消息接收与分发入口
• 统一解析 JSON / Multipart-FormData 请求。
• 将现场截图上传至 Cloudflare R2,生成公共 URL。
• 将消息入库 Supabase,并同步触发 SSE 广播与 WebPush 离线推送
app/api/sse/route.ts Server-Sent Events (SSE) 实时流接口
• 维护与各端客户端的长连接 HTTP 流。
• 15 秒定时 Post : ping 保持 HTTP 连接活性,防 Cloudflare/Nginx 代理超时截断。
lib/push.ts WebPush 离线推送核心模块
• 调用 web-push 库将告警 Payload 发送给客户端绑定的 Endpoint。
• 自动识别 HTTP 410/404 状态码并清理过期的离线设备 Token
public/sw.js PWA Service Worker 离线守护进程
• 在后台监听 push 事件,解析级别并呈现系统弹窗。
• 处理点击通知后的页面跳转或异步 API 响应 (notificationclick)。
• 更新/清除桌面 PWA 图标红点角标。
lib/win-notify.ts Windows 原生 Toast 通知脚本
• 识别 Windows/WSL 环境,构造 PowerShell 脚本。
• 使用系统合法的 PowerShell AUMID 绕过 Windows 通知中心静默拦截。
lib/db.ts & lib/supabase.ts 数据持久化与过期清理层
• 封装对 Supabase 的 CRUD 操作。
• 自动扫描并物理删除过期的告警记录以及同步清理 R2 存储桶中的关联截图。
lib/s3.ts Cloudflare R2 / AWS S3 图像存储
• 基于 @aws-sdk/client-s3 将截图归档至 picture/notify/YYYY-MM-DD/ 路径。
app/page.tsx Web 端控制台主界面
• 展示告警分析卡片、级别二级过滤与长文本折叠。
• 内部包含 drawFlashingFavicon 动态绘制高频呼吸闪烁 Favicon 脚本。

2. 安卓客户端 (NotifyGateway) 关键脚本作用

脚本文件路径 核心作用与实现逻辑
AndroidManifest.xml 权限与组件配置文件
• 申请 FOREGROUND_SERVICE_REMOTE_MESSAGING、开机自启、忽略电池优化等权限。
• 声明前台服务 NotifyService 与开机广播 BootReceiver
service/NotifyService.kt 后台双引擎长连接与保活服务
startForeground 挂载低干扰保活通知。
• 建立 OkHttp SSE 连接(20s 心跳 + 1s 无感自动重连)。
• 15s 智能探针(Fallback Polling)定时抓取兜底。
• 内置 300 容量的 LRU processedIds 集合防止重复触发。
receiver/BootReceiver.kt 开机/覆盖安装自启广播
• 监听 ACTION_BOOT_COMPLETEDMY_PACKAGE_REPLACED,在开机或应用更新后自动拉起离线后台服务
util/NotificationHelper.kt 分级通知提醒引擎
• 初始化 INFOWARNINGERRORCRITICAL 四大通知渠道。
• 配置各级别的优先度、标题前缀与专属脉冲震动节奏。
• 使用 Coil 异步下载现场大图并刷新展开通知卡片。
MainActivity.kt Android 客户端 UI 控制器
• 极客黑蓝风格列表展示,支持 10 条/页动态分页。
• 计算相对时间(如“刚刚”、“5分钟前”)与 TTL 动态过期倒计时(如 🟢 永久有效 / 🕒 还剩25分钟 / 🔴 已过期)。
• 动态构建告警级别、项目名、IP、账号等富文本 Badge。
model/NotificationPayload.kt 数据模型映射实体类
• 解析服务端下发的 JSON 数据(支持 message/descriptionimageUrl/image_url 等多别名适配)。

2.1 Supabase 开启表的实时推送教程(避坑与运维备忘录)

因为原来的方案是每10秒查询一次,消耗cloudflare 额度,cloudflare 每天请求10万次,一个设备就请求8000次了

为了确保未来换数据库重建表或部署新项目时一键复现,以下是关键配置步骤:


1. 开启表的实时推送(Realtime Replication)

安卓手机能收到实时通知的核心,是让 Supabase 数据库在有新通知插入(INSERT)时向外广播。

推荐方式(SQL 编辑器一键执行,最快):
  1. 登录 Supabase 控制台,进入你的项目。
  2. 点击左侧工具栏的 SQL Editor(代码图标 >_)。
  3. 点击 New query,粘贴并执行以下命令:
    -- 将 notifications 表加入到实时广播通道中
    alter publication supabase_realtime add table notifications
    
  4. 点击右下角绿色 Run 按钮,提示 Success. No rows returned 即代表配置完成。
可视化界面确认方式:
  1. 点击左侧 Database 模块下的 Publications
  2. 找到系统内置的 supabase_realtime
  3. 确保里面的 notifications 对应的开关处于 开启(绿色 Checked) 状态。

2. 表结构字段类型建议(防字段截断)

为了保证 actions 胶囊按钮网络图片与交互能够在安卓端 100% 完整解析,建议 notifications 表的字段类型设置如下:

列名 (Column) 类型 (Type) 说明
id text 消息唯一主键(如时间戳+随机字符)
title text 告警标题
message text 告警详情正文
level text 级别(info / warning / error / critical)
actions jsonb 交互按钮数组(必须是 jsonb,存储动作列表)
image_url text 现场截图 URL
image_key text R2/S3 存储键名
project text 所属项目名称
ip text 来源 IP
account text 关联账号
read boolean 是否已读
created_at int8numeric 毫秒时间戳
expire_at int8numeric 过期毫秒时间戳(0 为永久)
user_id uuidtext 所属用户 ID

3. RLS(Row Level Security 行级安全策略)设置

如果在连接 Supabase Realtime 时使用的是 anon key(匿名密钥),需要放开读取权限,或者直接关闭该表的 RLS:

在 Supabase 的 SQL Editor 中执行:

-- 方式一:直接关闭 notifications 表的 RLS(自用平台最省心)
alter table notifications disable row level security

:在你的 NotifyService.kt 中,目前连接使用的是 service_role 密钥,它天生具有绕过所有 RLS 的管理员最高权限,因此即使开启了 RLS 也能正常无阻通畅接收。


4. Supabase 免费版防休眠机制(重要提示)

Supabase 免费项目有一条平台策略:

如果项目连续 7 天没有任何数据库 API 写入或查询活动,项目会自动暂停休眠(Paused)。

应对方案
由于你搭建的是告警网关,只要你的服务器定时监控脚本逆变器或其他设备正常运行时有上报数据写入,数据库就会持续保持活跃状态,永远不会被休眠

如果长时间没有告警,也可以在服务器的 crontab 定时任务中每周发一次健康检查,即可保障终身免费畅通使用。

 

 


🚀 三、 秒级告警接入示例

网关部署完成后,你可以通过 cURL、Python 或任何监控工具发起告警:

发送一条高级别告警(带截图与 10分钟 TTL)

curl -X POST https://your-notify-domain.com/api/send \
  -H "Content-Type: application/json" \
  -d '{
    "title": "MySQL 主从同步延迟超标",
    "message": "当前主备延迟已达到 452 秒,超过阈值 300 秒!请检查网络与 I/O 状态。",
    "level": "critical",
    "project": "订单中心DB",
    "ip": "10.0.0.12",
    "account": "ops_admin",
    "ttl": 600,
    "imageUrl": "https://pub-r2.yourdomain.com/picture/demo-screenshot.png"
  }'

结果响应:

  • Android 端:前台服务收到 SSE 流或探针后,触发长脉冲强震动 + Heads-up 悬浮横幅,卡片显示 💥 CRITICAL🕒 还剩 10 分钟
  • Windows / PC 端:桌面右下角弹出原生 Toast 窗口,Web 界面 Tab 图标开始红光呼吸闪烁,PWA 图标数字角标 +1。

💡 四、 总结

通过 服务端(Serverless/SSE/WebPush)客户端(Android 14 前台服务/分级震动/LRU 去重) 的高度配合,本项目实现了:

  1. 全平台覆盖:Android + Windows + PWA + Web 控制台。
  2. 离线高可靠:即使不打开网页或 Android App 被杀,依然依靠保活服务与 WNS 离线通道送达。
  3. 精准告警:基于级别(Level)的视觉与声音/震动强弱区分,拒绝告警疲劳。