当前位置: 首页 > news >正文

企业H5站点升级PWA (九)

如何在我的 Service Worker 中实现推送通知?

下面给你一套最小可用的 Web Push 集成思路,结合你现有的 sw.jsindex.html,分成两块:

  1. 前端页面:注册推送、订阅并把订阅信息发给服务器。
  2. Service Worker:处理 push 事件并弹通知。

注意:真正“推送”是服务器发到浏览器的,你本地只能模拟(DevTools 里的“推送”按钮就是在触发 push 事件)。


1. 在 sw.js 里处理 push 通知

先在你现有的 sw.js 末尾增加 push 和通知点击事件处理:

self.addEventListener('push', (event) => {// 约定服务器发送的数据为 JSON 字符串let data = {};if (event.data) {try {data = event.data.json();} catch {data = { body: event.data.text() };}}const title = data.title || 'DensenApp 通知';const options = {body: data.body || '您有一条新消息。',icon: data.icon || './densen26.jpg',badge: data.badge || './densen26.jpg',data: {url: data.url || './index.html', // 点击通知要打开的地址...data}};event.waitUntil(self.registration.showNotification(title, options));
});self.addEventListener('notificationclick', (event) => {event.notification.close();const url = event.notification.data?.url || './index.html';event.waitUntil(self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {// 如果已有同源窗口,直接聚焦并导航for (const client of clientList) {if ('focus' in client) {client.focus();if (url && 'navigate' in client) {client.navigate(url);}return;}}// 否则新开一个窗口if (self.clients.openWindow && url) {return self.clients.openWindow(url);}return null;}));
});

这样,收到 push 时就会弹系统通知;点击通知会打开(或切换到)你的页面。


2. 在页面端发起推送订阅

2.1 准备 VAPID 公钥

Web Push 需要 VAPID 公私钥对,一般在服务器(.NET)生成:

  • 可以用 ASP.NET Core / 控制台配合 WebPush 库生成;
  • 这里只假定你已经拿到一个 Base64 URL 安全格式的公钥字符串,例如:
BPx...你的VAPID公钥...abc

下面代码里用 const VAPID_PUBLIC_KEY = '...'; 占位。

2.2 在 index.html / 某个 JS 里增加订阅逻辑

建议在你当前 index.html 里已有的 Service Worker 注册逻辑旁边,增加一个“初始化推送”的调用。

把原来的 <script> 末尾稍微整理一下:

    <script src="bootstrap.bundle.min.js"></script><script src="./js/index.js"></script><script>const VAPID_PUBLIC_KEY = '在这里填你的VAPID公钥';async function initServiceWorkerAndPush() {if (!('serviceWorker' in navigator)) {return;}// 注册 SWconst registration = await navigator.serviceWorker.register('./sw.js');console.log('Service Worker 注册成功:', registration.scope);// 监听 SW 激活刷新navigator.serviceWorker.addEventListener('message', (event) => {if (event.data?.type === 'SW_ACTIVATED') {console.log('Service Worker 已更新到版本:', event.data.version);window.location.reload();}});// 申请通知权限const permission = await Notification.requestPermission();if (permission !== 'granted') {console.warn('用户拒绝通知权限');return;}// 订阅 pushconst subscription = await registration.pushManager.subscribe({userVisibleOnly: true,applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)});console.log('Push 订阅成功:', subscription);// TODO: 把 subscription 发送到你的服务器保存起来// 例如:// await fetch(API_BASE + '/api/push/subscribe', {//     method: 'POST',//     headers: { 'Content-Type': 'application/json' },//     body: JSON.stringify(subscription)// });}function urlBase64ToUint8Array(base64String) {const padding = '='.repeat((4 - (base64String.length % 4)) % 4);const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');const rawData = window.atob(base64);const outputArray = new Uint8Array(rawData.length);for (let i = 0; i < rawData.length; ++i) {outputArray[i] = rawData.charCodeAt(i);}return outputArray;}window.addEventListener('load', () => {initServiceWorkerAndPush().catch(err => {console.error('初始化 Service Worker / Push 失败:', err);});});</script>
</body>
</html>

要点:

  • Notification.requestPermission() 会弹系统权限对话框;
  • registration.pushManager.subscribe(...) 创建订阅;
  • subscription 需要发给你的服务器保存(包含 endpoint + 密钥)。

3. 服务器端发送 Web Push(简要)

你后端是 .NET,可以用 WebPush.Net 之类的库向浏览器推送:

using WebPush;var subject = "mailto:you@example.com";
var publicKey = "<与你前端相同的VAPID公钥>";
var privateKey = "<VAPID私钥>";var client = new WebPushClient();
var vapidDetails = new VapidDetails(subject, publicKey, privateKey);// subscriptionJson 是你从前端保存的 Subscription 对象 JSON
var subscription = JsonSerializer.Deserialize<PushSubscription>(subscriptionJson);var payload = new
{title = "DensenApp 通知",body = "有新的订单,请及时处理",url = "https://你的站点地址/orders.html"
};await client.SendNotificationAsync(subscription,JsonSerializer.Serialize(payload),vapidDetails);

这条消息就会触发前面 sw.js 里的 push 事件,然后弹通知。


4. 开发时如何快速验证

  1. 本地调试

    • 必须在 https://http://localhost 下访问;
    • 允许浏览器通知;
    • 看 console 中是否有“Push 订阅成功”。
  2. 用 DevTools 的“推送”按钮模拟

    • 在 Application → Service Workers 面板;
    • 输入如 {"title":"测试","body":"来自DevTools的推送"}
    • 点击“推送”,应看到通知弹出。

如果你希望,我可以再帮你把服务器端 .NET 发送推送那块按你现在的 WebAPI 结构(看看 WebApp.cs)嵌一段实际的控制器示例。

http://www.jsqmd.com/news/392424/

相关文章:

  • 题解:洛谷 P1719 最大加权矩形
  • 题解:洛谷 P8218 【深进1.例1】求区间和
  • 题解:洛谷 P1069 [NOIP 2009 普及组] 细胞分裂
  • Android Framework 开发工程师
  • AI原生应用个性化定制,提升产品差异化
  • 价值投资的核心原则:安全边际
  • 惊!生成随机数居然不用随机数库?4行代码吃透随机本质
  • RabbitMQ在大数据数据可视化中的应用
  • 题解:洛谷 P1593 因子和
  • 数据产品国际化:多语言与多地区支持方案
  • 细胞生物化学仿真软件:VCell_(3).用户界面和基本操作
  • 一文搞懂【RAG技术】- 趣味解读RAG 高效召回秘籍之索引扩展:核心原理+实战案例
  • 细胞生物化学仿真软件:VCell_(1).VCell软件概述
  • 企业H5站点升级PWA (八)
  • 题解:洛谷 P1072 [NOIP 2009 提高组] Hankson 的趣味题
  • 移动开发领域 Gradle 与 CI_CD 的集成方案
  • 题解:洛谷 P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题
  • 俄罗斯方块C++命令行版本 - ace-
  • 题解:洛谷 P3383 【模板】线性筛素数
  • 快速制作 虚拟形象项目 MotionPNGTuber
  • 软件测试一篇通
  • 题解:洛谷 P2822 [NOIP 2016 提高组] 组合数问题
  • 【RL+MCS】基于深度强化学习的能效链路自适应联合功率分配与调制编码方案选择【附MATLAB代码】
  • 学会正确看待自己的工作
  • ISAC波形设计新突破!概率去噪增强的PDISAC兼顾感知与通信双性能【附MATLAB+pyython代码】
  • 题解:洛谷 P1983 [NOIP 2013 普及组] 车站分级
  • 这几天的大模型圈,真的有点“卷”过头了
  • 企业H5站点升级PWA (五)
  • 题解:洛谷 P1017 [NOIP 2000 提高组] 进制转换
  • 企业H5站点升级PWA (六)