有三种用户在等待你的应用告诉他们一些事情:正盯着页面看的那一种,公司代理不放行 WebSocket 的那一种,以及两个小时前就关掉了浏览器的那一种。sgcWebSockets 2026.10 把这三种都覆盖到了。
不放行 WebSocket 的代理
Server-Sent Events 就是普通的 HTTP:一个保持打开的 GET 请求,加上一段文本流。链路上的任何一环都没有理由拒绝它。sgcHTML 引擎现在可以用这种方式来传递更新,而不必依赖 WebSocket,并且可以让页面自己来决定用哪一种:
FEngine.SSE.Enabled := True;
FEngine.SSE.Endpoint := '/events';
FEngine.SSE.PostEndpoint := '/events/send';
FEngine.SSE.ReplaySize := 100;
FTemplate.Transport := htAuto; { htWebSocket, htSSE or htAuto }
使用 htAuto 时,页面会先打开一个 WebSocket,一旦不行就自动回退到事件流。重放缓冲区意味着一个短暂掉线的读者会补上离开期间错过的更新,而不是留下一个空洞。
值得强调的一点是:这在普通 HTTP 服务器上也能工作。向页面推送更新已经完全不再需要 WebSocket 服务器了。
已经关闭浏览器的用户
Web Push 能够触达一个不在你页面上的浏览器,甚至是一个根本没有运行的浏览器。页面负责订阅,你的应用把订阅保存在它存放数据的任何地方,然后一次调用就能发送通知:
uses
sgcHTML_WebPush;
FWebPush := TsgcHTMLWebPush.Create(Self);
FWebPush.Enabled := True;
FWebPush.VAPIDPublicKey := ReadSetting('vapid.public');
FWebPush.VAPIDPrivateKey := ReadSetting('vapid.private');
FWebPush.Subject := 'mailto:info@example.com';
FWebPush.OnSaveSubscription := DoSaveSubscription;
FWebPush.OnLoadSubscriptions := DoLoadSubscriptions;
FWebPush.OnDeleteSubscription := DoDeleteSubscription;
FEngine.WebPush := FWebPush;
FWebPush.Send('user-42', 'Order 1042 shipped',
'It left the warehouse this morning.', '/orders/1042');
库负责协议本身:加密后的负载、VAPID 签名、TTL 以及紧急程度请求头。你的应用负责存储,通过三个事件来完成,因为订阅信息存放在哪里,是只有你才能做出的决定。一个已被推送服务下线的订阅,会通过 OnSubscriptionExpired 返回给你,方便你将其删除。
在两者之间做出选择的组件
拥有两条通道,只有在有东西负责选择时才有用。通知组件现在就承担了这个角色:正在看页面的用户会在页面内收到通知,不在看页面的用户则会在应用允许的情况下收到一条 web push。一次通知,一次调用,用户不会被重复告知。
以及围绕它的两个组件
一个通知收件箱。一个带未读徽章的铃铛图标,显示某个用户的通知,支持标记已读和清空,这样一条被错过的通知就不会变成一条丢失的通知。
一个通知偏好设置表。让用户在这里勾选每种通知要如何送达给自己。这是所有人都会一拖再拖的部分,也是让你不会因为向没有要求接收推送的人推送消息而惹上麻烦的部分。
两者在每个版本中都可以工作,无论是通过 WebSocket 还是通过 Server-Sent Events。
版本
Server-Sent Events、收件箱和偏好设置表都是 sgcHTML 的一部分。Web Push 本身,也就是能触达已关闭浏览器的那部分,需要 SGC_WEBPUSH,也就是 Enterprise 和 All-Access 版本。
升级
这里的所有功能默认都是关闭的。在你设置 Transport、指定一个 WebPush,或者把两个新组件中的一个放到窗体上之前,现有页面会保留原有的 WebSocket 传输方式,渲染出同样的内容。
延伸阅读
观看视频
关于此功能的简短视频发布在eSeGeCe 频道上。
有问题、反馈,或需要迁移方面的帮助?欢迎联系我们 — 你会收到编写这些代码的人的回复。
