- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
推送通知在现代网络上很常见。即使您的网站实际上并未打开,它们也能让您及时向用户传达信息。用户的浏览器处理传入的推送事件并使用系统 UI 界面(如 Windows 操作中心和 Android 锁屏)显示通知。
在您的网站或 PWA中实施 Web Push需要结合两个不同的浏览器 API。负责订阅和接收通知的代码使用service workers的Push API组件。此代码在后台持续运行,并在需要处理新通知时由浏览器调用。
当接收到一个事件时,服务工作者应该使用通知 API来实际显示通知。这会通过操作系统级界面创建视觉警报。
这是让 Web Push 在您的网站上运行的完整指南。我们假设您已经拥有一个服务器端组件,可以注册推送订阅并发送您的警报。
让我们从服务工作者开始。服务工作者有多个角色——他们可以缓存数据以供离线使用、运行定期后台同步以及充当通知处理程序。服务工作者使用事件驱动的架构。一旦被站点注册,用户的浏览器将在其订阅的事件生成时在后台调用服务工作者。
对于 Web Push,需要一个核心事件:push. 这会接收一个PushEvent对象,该对象允许您访问从服务器推送的有效负载。
self.addEventListener("push", e => {
const payload = JSON.parse(e.data.text());
e.waitUntil(self.registration.showNotification(
payload.title,
{
body: payload.body,
icon: "/icon.png"
}
));
});
上面的代码设置了一个能够对传入的推送事件做出反应的服务工作者。它期望服务器发送如下所示的 JSON 有效负载:
{
"title": "Title text for the notification",
"body": "This is the longer text of the notification."
}
当接收到推送事件时,服务工作者通过调用其属性showNotification()上可用的函数来显示浏览器通知。self.registration该函数包含在一个waitUntil()调用中,因此浏览器在终止服务工作者之前等待显示通知。
该showNotification()函数有两个参数:通知的标题文本和一个选项对象。在这个例子中传递了两个选项,一些较长的正文和一个在通知中显示的图标。还有许多其他选项可供您设置振动模式、自定义徽章和交互要求。并非所有浏览器和操作系统都支持 API 公开的所有功能。
通过在主 JavaScript 中注册它来完成代码的 service worker 端:
if (navigator.serviceWorker) {
// replace with the path to your service worker file
navigator.serviceWorker.register("/sw.js").catch(() => {
console.error("Couldn't register the service worker.")
});
}
此代码应在每个页面加载时运行。它确保浏览器支持服务工作者,然后注册工作者文件。只要服务器副本与当前安装的版本存在字节差异,浏览器就会自动更新服务工作者。
现在您需要订阅浏览器以推送通知。以下代码属于您的主 JavaScript 文件,在服务工作者之外。
async function subscribeToPush() {
if (navigator.serviceWorker) {
const reg = await navigator.serviceWorker.getRegistration();
if (reg && reg.pushManager) {
const subscription = await reg.pushManager.getSubscription();
if (!subscription) {
const key = await fetch("https://example.com/vapid_key");
const keyData = await key.text();
const sub = await reg.pushManager.subscribe({
applicationServerKey: keyData,
userVisibleOnly: true
});
await fetch("https://example.com/push_subscribe", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
endpoint: sub.endpoint,
expirationTime: sub.expirationTime,
keys: sub.toJSON().keys
})
});
}
}
}
}
然后调用你的函数来订阅浏览器推送通知:
await subscribeToPush();
让我们来看看订阅代码在做什么。前几行检查是否存在服务工作者,检索其注册,并检测推送通知支持。pushManager不会在不支持 Web Push 的浏览器中设置。
调用pushManager.getSubscription()会返回一个 Promise,该 Promise 解析为描述浏览器当前对您的站点的推送订阅的对象。如果这已经设置,我们不需要重新订阅用户。
真正的订阅流程从服务器的 VAPID 密钥的获取请求开始。VAPID 规范是一种让浏览器验证推送事件实际上来自您的服务器的机制。您应该公开一个提供 VAPID 密钥的服务器 API 端点。这是给pushManager.subscribe()函数的,因此浏览器知道要信任的密钥。单独的userVisibleOnly选项表示我们只会显示在屏幕上明显显示的通知。
该pushManager.subscribe()调用返回一个描述您的新订阅的PushSubscription对象。此数据在另一个获取请求中发送到服务器。在真正的应用程序中,您还需要发送活动用户的 ID,以便您可以将推送订阅链接到他们的设备。
用于向用户发送推送通知的服务器端代码应如下所示:
每个订阅endpoint都将引用浏览器供应商的通知传递平台。此 URL 已包含订阅的唯一标识符。当您向端点发送有效负载时,浏览器的后台进程最终将接收数据并调用您的服务工作者。对于 Android 上的 Chrome,浏览器进程直接与系统通知守护进程集成。
设置订阅流程时,请记住用户必须在注册完成之前确认浏览器权限提示。许多浏览器会自动隐藏或拒绝未经请求的权限请求;无论如何,要求用户在他们登陆您的网站的那一刻进行订阅可能无法提供您想要的结果。
通过将订阅请求与直接用户操作相结合,您可以获得成功注册的最佳机会。考虑提供一个应用内横幅,说明启用通知的好处并提供“立即启用”按钮。您可以使用上面显示的功能检查用户是否已经订阅并隐藏横幅pushManager.getSubscription()。
单击启用按钮应调用您的订阅函数。在浏览器设置注册并且您的网络调用完成时,该过程可能需要几秒钟。在此期间显示加载微调器将有助于让用户了解情况。
还应该为用户提供取消订阅的方法。尽管他们可以随时撤销浏览器权限,但有些用户会寻找应用内选项,尤其是当他们将您的网站安装为 PWA 时。
这是一个简单的取消订阅实现:
async function unsubscribePush() {
const reg = await navigator.serviceWorker.getRegistration();
const subscription = await reg.pushManager.getSubscription();
if (subscription) {
await subscription.unsubscribe();
await fetch(`https://example.com/push_unsubscribe/${subscription.endpoint}`, {method: "DELETE"});
}
else {
// already subscribed
}
}
调用unsubscribe()aPushSubscription取消订阅,将浏览器恢复到默认状态。您的服务人员将停止接收push事件。订阅的端点被发送到您的服务器,因此您可以将其从数据存储中删除,并避免将数据发送到现在已失效的 URL。
您可能已经注意到浏览器创建expirationTime的对象的属性。PushSubscription这并不总是被设置;如果是,设备将在此时间后停止接收通知。
实际上,expirationTime目前主要浏览器中并未使用。Chrome 生成的令牌在手动取消订阅之前不会过期expirationTime,所以总是如此null。Firefox 也没有设置expirationTime,但它的通知服务可以在其生命周期内替换订阅。
pushsubscriptionchange您可以通过在您的服务工作者中实现事件来响应浏览器更改您的活动推送订阅。不幸的是,此事件有两个版本:Firefox 当前使用的原始实现,以及尚未在任何浏览器中支持的新 v2。
原始规范存在严重的可用性问题,因此难以响应事件。当您收到 v1 事件时,浏览器已删除原始订阅,您需要手动创建一个新订阅。问题是无法访问过期订阅,您无法向服务器发出“替换”请求——您无法访问旧endpointURL。
v2 规范通过提供具有oldSubscription和newSubscription属性的事件来解决这个问题。当您收到事件时,旧订阅已被取消,但您仍然可以访问其属性。新订阅现在由浏览器为您创建。
pushsubscriptionchange这是使用新规范实施的示例:
self.addEventListener("pushsubscriptionchange", e => {
e.waitUntil(async () => {
await fetch("https://example.com/push_change", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
auth: (e.newSubscription.toJSON().keys?.auth || null),
endpoint: e.newSubscription.endpoint,
endpointOld: e.oldSubscription.endpoint,
expirationTime: e.newSubscription.expirationTime,
p256dh: (e.newSubscription.toJSON().keys?.p256dh || null)
})
});
});
});
端点是唯一的,因此您的服务器可以查找旧订阅并使用新订阅的属性更新其属性。如果您还想添加对旧规范的支持,则需要手动跟踪推送 API 之外的活动订阅端点。将其存储到localStorage或 IndexedDB 将允许您在pushsubscriptionchange处理程序中访问它,以便您可以要求服务器替换订阅。
修订后的规范比旧版本更容易实施。尽管浏览器尚不支持它,但还是值得将它添加到您的服务工作者中。几行代码将使您的推送处理针对新的浏览器版本进行验证。
推送通知可以包括让用户立即采取行动的交互式按钮。这是一个showNotification()创建一个调用:
self.registration.showNotification(
"Notification with actions",
{
body: "This notification has a button.",
actions: [
{
action: "/home",
title: "Go to Homescreen",
icon: "/home.png"
}
]
}
);
每个通知可以包含多个操作,每个操作都带有标签、图标和action. 后一个属性应该标识您的应用程序可以响应用户的按下而启动的操作。
当用户点击一个动作时,你的 service worker 会收到一个notificationclick事件:
self.addEventListener("notificationclick", e => {
const uri = e.action;
const notification = e.notification;
notification.close();
clients.openWindow(`${self.location.origin}${action}`);
});
我们使用该action属性来声明用户可以导航到的 URI。按下通知时,URI 会打开一个新选项卡。调用notification.close()确保通知也被忽略。否则,某些平台会让用户手动将其滑走。
如果您以前没有使用过相关的 API,那么实现 Web 推送可能会让人望而生畏。除了技术问题之外,您还应该将用户体验放在首位,并确保您传达为什么值得启用通知。
订阅和取消订阅推送发生在应用程序的主要 JavaScript 代码中,使用navigator.serviceWorkerAPI。响应新推送事件并显示浏览器通知的代码位于 service worker 本身中。
现在大多数主要的 Web 浏览器都支持 Web Push,Safari 是一个突出的例外。请记住,通知将在每个浏览器和操作系统系列中呈现不同,因此不要假设showNotification()API 的特定功能将普遍可用。
我有这个网站,这个特定页面是安全的,但是当它回发时,它回发到一个不安全的页面。如何解决? 我正在使用 ASP.NET 向导。我有这个页面 - checkout.aspx,页面包含这个控件 checko
我有 2 个 azure 网站 - 两个独立的项目 我现在有 2 个网址: myazurewebsite.azurewebsites.net myazureblog.azurewebsites.net
我有 2 个 azure 网站 - 两个独立的项目 我现在有 2 个网址: myazurewebsite.azurewebsites.net myazureblog.azurewebsites.net
环境: 旧网站: React 托管在 Heroku URL( http://sameurl.com ) 新网站: Java 托管在 Heroku URL ( http://sameurl.com )
我已在 Windows Azure 上注册了一个测试帐户来对其进行测试。我构建了一个 Hello world ASP.NET Web 应用程序 + 数据库只是为了测试。 我安装了 Visual Stu
我有一个可以收集和显示各种测量值的产品(不会详细介绍)。正如人们所期望的那样,显示部分是一个数据库+建立在其之上的网站(使用 Symfony)。 但是,我们可能还会创建一个 API 来向第三方公开数据
这个问题在这里已经有了答案: Software keyboard resizes background image on Android (16 个答案) 关闭 8 年前。 我有一个类似的问题:So
这个问题似乎很常见,但我真的无法根据现有答案解决问题。 我有一个简单的 maven 项目,没有任何复杂的部署配置等,并且想在点击“mvn site”时生成一个 Maven CheckStyle 报告。
有没有人看过有关何时进行横向扩展与纵向扩展的最佳选择的任何分析或信息。什么时候一个比另一个更有意义。 目前,在标准模式和基本模式下,2 个小型实例的费用与 1 个中型实例的费用相同。 拥有 2 个小型
有没有办法找到 azure 网站何时停止? (我通过门户网站停止了网站,但我不记得是什么时候......) 我正在寻找一些日志,但没有找到任何有用的内容。 谢谢。 最佳答案 您拥有的最接近的是 azu
我目前在 Azure VM 的 IIS 中拥有一个网站。我已将该站点复制到 2 个可用区域中的 2 个虚拟机上。 这可以保护网站免遭停机。 我需要为高负载时刻实现一些可扩展性。这似乎就是创建音阶集的目
我有一个托管在 Azure 上的网站 ( http://mike-ward.azurewebsites.net/ )。我从 Azure 门户设置了一个指向(引用?)我的网站的 Azure CDN。根据
我有一个 Azure 网站(不是 Web 角色),有 2 个槽:生产和暂存。 我只想为生产插槽启用 CDN,而不是为登台启用,问题是我找不到识别主机插槽的方法。 RoleEnvironment 不可用
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等建议的问题。您可以编辑问题,以便可以用事实和引用来回答它。 4年前关
我们正在考虑将一些网站从 Azure 云服务迁移到 Azure 网站(事情似乎就是这样进行的)。显然,我们被明确告知云服务不会保留文件系统状态,因为它们会在机器故障时重新部署。 我假设网站是基于 Bl
我有一个 Azure 网站,需要使用在 VM 上运行的 Elasticsearch 服务。 虽然我需要能够锁定对 Elasticsearch 的访问,以便只有 Azure 网站可以访问它,但我似乎无法
我有一个 azure 网站,位于 yis3.azurewebsites.net - 我已将其提升为“共享”网站,以便我可以使用自定义域。我拥有从 123-reg.co.uk 购买的域名 yorkshi
我正在使用 abcPDF 动态创建 PDF。 我想保存这些 PDF,以便客户随时检索。最简单的方法(也是我现在在当前服务器上所做的方法)是将完成的 PDF 保存到文件系统。 看来我一直坚持使用 blo
我们正在尝试了解 Windows Azure 管理 API 为 Azure 网站(而非 Webroles)返回的监控数据的复杂性 例如,下图描述了为 CPUTime 检索的数据点。它似乎表明,在晚上
看起来真的很愚蠢,因为我找不到它: 门户网站似乎不太直观,我如何为一个“网站”付费并在其中运行最多 500 个网站?我想当我通过单击左下角的加号添加“网站”时,我添加了整个虚拟机而不是子站点。如何仅添
我是一名优秀的程序员,十分优秀!