深入ServiceWorker,消息推送,后台同步,一网打尽!

丰富的线上&线下活动,深入探索云世界

做任务,得社区积分和周边

最真实的开发者用云体验

让每位学生受益于普惠算力

让创作激发创新

资深技术专家手把手带教

遇见技术追梦人

技术交流,直击现场

海量开发者使用工具、手册,免费下载

极速、全面、稳定、安全的开源镜像

开发手册、白皮书、案例集等实战精华

为开发者定制的Chrome浏览器插件

上一章讲到了ServiceWorker的基础使用,但是它的功能不仅仅只有这些,还有很多很多,比如消息推送,后台同步,甚至还有WebRTC,这一章我们来进阶ServiceWorker。

在开始之前,我们先做一下前期的准备,还是使用我上一篇的例子,但是我们需要删除service-worker.js里面的缓存代码,因为这一章用不上,新看到的小伙伴可以直接用我下面的代码也行:

Title消息推送使用ServiceWorker是一定要了解消息推送的,因为它是ServiceWorker的一个重要功能,它可以让你的网站在用户不在的时候,也能够接收到消息,这对于一些即时通讯的网站来说,是非常重要的。

按照正常的消息推送流程,我们需要经历下面几个步骤:

在讲推送流程之前,我们先来体验一下消息推送的快感。

啥也不多说,直接上代码:

上面的方法直接让我们在window上显示了一个消息,但是这个消息是没有任何交互的,我们可以通过Notification对象来实现交互:

这样我们就可以在消息上添加交互了,但是这个交互是没有任何效果的,我们需要通过监听notificationclick事件来实现交互:

//service-worker.js//监听notificationclick事件self.addEventListener('notificationclick',(event)=>{//判断点击的是哪个按钮if(event.action==='yes'){console.log('yes');}elseif(event.action==='no'){console.log('no');}});这个时候我们就可以在控制台看到点击的是哪个按钮了,接下来我们就来认识一下showNotification方法。

showNotification方法是ServiceWorkerRegistration对象的一个方法,它可以用来显示消息,直接看函数签名:

通过上述的实验代码,不知道大家有没有发现一个问题,就是showNotification方法调用出来的消息是直接显示在window上的,而不是显示在浏览器的通知栏上。

这是因为消息推送是浏览器行为,作用在window系统上,而不是作用在网页上。

通过这个案例,有没有产生一个想法,就是大家在写业务代码的时候,遇到消息通知都是自己手写一个弹窗消息,切换个网页就看不到了;

这个时候我们使用showNotification方法,直接推送到window上,虽然样式不能自定义,但是是不是逼格更高呢?

而我们的showNotification方法,其实是通过Notification对象来实现的,点到为止,继续学习ServiceWorker。

为什么要先体验消息推送的效果呢,再来讲消息推送的流程呢?

因为不想打击大家的热情,消息推送因为会被墙,所以在国内没有多少人使用,所以我们先体验一下,再来讲消息推送的流程。

现在我们直接上代码来查看整体流程是怎么样的:

if('serviceWorker'innavigator){//1.注册`ServiceWorker`获得`registration`对象//2.通过`registration`对象获得`PushManager`对象//3.通过`PushManager`对象订阅消息推送,获得`subscription`对象//4.将`subscription`对象发送给服务器,由服务器保存//5.服务器通过`subscription`对象推送消息//6.`ServiceWorker`通过监听`push`事件,获得推送的消息//7.`ServiceWorker`通过`showNotification`方法,显示消息//1.注册`ServiceWorker`获得`registration`对象navigator.serviceWorker.register('/service-worker.js',{scope:'/'}).then((registration)=>{//2.通过`registration`对象获得`PushManager`对象constpushManager=registration.pushManager;//3.通过`PushManager`对象订阅消息推送,获得`subscription`对象pushManager.subscribe({userVisibleOnly:true,applicationServerKey:''}).then((subscription)=>{//4.将`subscription`对象发送给服务器,由服务器保存console.log(subscription);});});}前面的四步都是在客户端完成的,这里的关键在于第三步,通过PushManager对象订阅消息推送,获得subscription对象。

我们先来看一下subscribe方法的参数和简介:

interfacePushSubscriptionOptions{userVisibleOnly:boolean;applicationServerKey:BufferSource;}interfacePushManager{/***订阅消息推送*@paramoptions*options.userVisibleOnly:是否只有用户可见*options.applicationServerKey:服务器公钥*@returns{Promise}*/subscribe(options:PushSubscriptionOptions):Promise;}这里的options在文档上显示是可选参数,但是在部分浏览器上是必填参数,所以我们在调用subscribe方法的时候,需要传入options参数。

参数介绍:

这里的重点就是applicationServerKey,这个是由我们自己生成的,接下来我们来看一下如何生成。

我们可以通过web-push这个库来生成服务器公钥,这个库是Google开发的,旨意是打通多端消息推送的通道,它提供了一些工具,可以帮助我们生成服务器公钥,以及发送推送消息。

安装web-push会被墙,可以通过切换npm源来解决:

npminstallweb-push安装完成后,我们就可以使用web-push来生成服务器公钥了:

constwebpush=require('web-push');//生成服务器公钥constvapidKeys=webpush.generateVAPIDKeys();console.log(vapidKeys);我们也可以全局安装web-push,然后通过命令行来生成服务器公钥:

上面生成的密钥对会有一个公钥和一个私钥,私钥放在服务器保存,公钥用于注册推送订阅:

pushManager.subscribe({userVisibleOnly:true,applicationServerKey:'BHXrxJPYpQSwGMwcN-HprCaU_Po9POIUvqWFLFq9UUNHP5SNJKxk_Io59y8_twMTOuB5SbpbcPBwHFo2kBUj7vQ'}).then((subscription)=>{//4.将`subscription`对象发送给服务器,由服务器保存console.log(subscription);});上面注册成功后,会返回一个subscription对象,这个对象就是推送订阅,我们需要将这个对象发送给服务器,由服务器保存,用于后续推送消息。

有时候注册过了如果再重复注册会报错,可以通过pushManager.getSubscription()来获取已经注册的subscription对象。

pushManager.getSubscription().then((subscription)=>{if(subscription){//这里subscription就是已经注册的subscription对象return;}pushManager.subscribe({userVisibleOnly:true,applicationServerKey:'BHXrxJPYpQSwGMwcN-HprCaU_Po9POIUvqWFLFq9UUNHP5SNJKxk_Io59y8_twMTOuB5SbpbcPBwHFo2kBUj7vQ'}).then((subscription)=>{console.log(subscription);});});发送推送消息推送消息我们同样也是通过web-push来发送,它提供了一个sendNotification()方法,可以帮助我们发送推送消息。

这里我们通过node服务来写一个简单的推送消息的接口:

ServiceWorker监听推送消息,我们需要在ServiceWorker中注册push事件,然后在push事件中处理推送消息,也就是最开始提到的showNotification()方法。

自此一整套的消息推送和接收的流程就走完了,但是为什么要订阅推送消息?为什么我自己的服务器还需要申请啥GCMApiKey?

这就要说到消息推送的很多知识了,这里不宜过多的展开,有兴趣的可以自行了解。

我们这里需要了解的是订阅到服务器推送之间的过程倒是是什么样的,为什么我说推送消息会被墙,为什么我们推送消息会不成功?

这里我们直接看下面的流程图:

graphTDA[订阅推送消息]-->B[FCM服务器]B-->C1[验证不通过抛出异常]B-->C[返回subscription对象]C-->D[将subscription对象保存到服务器]D-->E[服务器向FCM服务器发送推送消息]E-->F[FCM服务器将消息直接推送给浏览器]F-->G[浏览器接收到推送消息调用push回调]F-->G1[浏览器不在线推送消息会在浏览器上线时通过notificationcallback回调]G-->H[执行push事件里面的回调函数]可以看到服务和浏览器之间是没有直接的通信的,而是通过FCM服务器来进行通信的;

而FCM服务器是谷歌的服务器,所以我们不管是订阅还是推送消息都需要通过谷歌的服务器,这就是为什么我们推送消息会被墙的原因;

PC不像移动端,你的网页或者浏览器不会一直开着,所以你的网页或者浏览器不在线的时候,你的推送消息是不会被推送到你的浏览器的,这个时候你的推送消息就会被FCM服务器保存起来,等你的网页或者浏览器上线的时候,FCM服务器会通过notificationcallback回调来推送消息到你的网页或者浏览器。

self.addEventListener('notificationcallback',function(event){constdata=event.data.json();self.registration.showNotification(data.title)});注意:这个回调是在离线的时候有推送消息,然后在你的网页上线的时候才会触发,如果你的网页一直在线,那么这个回调是不会触发的。

ok,到这里我们已经了解了推送消息的一些知识,我们继续下面的环节。

上面讲到了push事件的监听,现在就还剩下sync事件的监听了,sync事件是在ServiceWorker中注册的,当我们调用navigator.serviceWorker.ready方法后,就可以通过registration.sync.register()方法来注册sync事件了。

//注册sync事件navigator.serviceWorker.ready.then((registration)=>{returnregistration.sync.register('sync');});这里我们注册了一个sync事件,这个事件的名字叫sync,这个名字是自己定义的,可以随便定义,但是需要注意的是,这个名字是全局唯一的,如果你注册了一个sync事件,那么下次再注册的时候,就不能再注册一个sync事件了,否则会报错。

上面注册好了之后,就需要在ServiceWorker中监听这个事件了:

//监听sync事件self.addEventListener('sync',(event)=>{if(event.tag==='sync'){event.waitUntil(//同步数据syncData());}});相对于push事件,sync事件的监听就简单多了,我们只需要判断一下事件的名字,然后执行对应的操作就可以了。

使用sync事件首选需要注册一个sync事件,通过registration.sync.register()方法来注册;

上面使用到navigator.serviceWorker.ready是用来确保ServiceWorker已经注册成功,它会返回一个不会失败的Promise对象,如果没有注册成功,那么就会一直处于pending状态。

在ServiceWorker中监听sync事件,通过self.addEventListener('sync',callback)方法来监听,这个callback函数会接收一个event对象,通过event.tag来判断事件的名字,然后执行对应的操作。

看名字就知道,sync事件是用来同步数据的,那么我们什么时候需要同步数据呢?

sync的使用场景有很多,我下面列举几个:

通常我们可以使用这个事件来通知ServiceWorker同步数据,或者更新缓存,继续拿我之前的百万数据的例子来说;

百万数据很大,在上一篇中我们将数据缓存下来了,但是如果数据发送了变化,那么我们就需要更新缓存,这个时候就可以使用sync事件来通知ServiceWorker更新缓存。

//main.js//请求后台查询数据是否有变化fetch('/api/check').then((res)=>{returnres.json();}).then((data)=>{if(data.hasChange){//有变化,注册sync事件navigator.serviceWorker.ready.then((registration)=>{returnregistration.sync.register('sync');});}});//service-worker.js//监听sync事件self.addEventListener('sync',(event)=>{if(event.tag==='sync'){event.waitUntil(//同步数据syncData());}});//同步数据functionsyncData(){//请求后台获取数据returnfetch('/getData').then((res)=>{returnres.json();}).then((data)=>{//更新缓存caches.open('my-caches').then((cache)=>{cache.put('/getData',newResponse(JSON.stringify(data)));});});}上面的代码中,我们在main.js中请求后台查询数据是否有变化,如果有变化,那么就注册一个sync事件,然后在ServiceWorker中监听这个事件,当事件触发的时候,就会执行syncData方法,这个方法中会请求后台获取数据,然后更新缓存。

本文的最开始给了一段注释的代码,这段代码是用来更新ServiceWorker的,就是下面这段代码:

navigator.serviceWorker.getRegistrations().then((registrations)=>{for(letregistrationofregistrations){registration.unregister()}});这段代码并不是用来更新ServiceWorker的,而是用来卸载ServiceWorker的,所以最开始我注释说明是开发阶段使用的,因为我们在开发阶段,经常会修改ServiceWorker的代码,如果不卸载ServiceWorker重装很有可能缓存没有清除,导致我们看到的效果和预期的不一样。

但是在生产环境中,我们肯定是不能轻易卸载ServiceWorker的,当然ServiceWorker也提供了更新的方法,我们可以通过ServiceWorker的update方法来更新ServiceWorker。

//更新ServiceWorkernavigator.serviceWorker.getRegistration().then((registration)=>{registration.update();});上面的代码中,我们通过getRegistration方法获取ServiceWorker的注册对象,然后调用update方法来更新ServiceWorker。

同样,是否需要更新ServiceWorker,也是需要我们自己来判断的,比如我们可以通过ServiceWorker的scriptURL属性来判断ServiceWorker的版本,如果版本不一致,那么就更新ServiceWorker。

//更新ServiceWorkernavigator.serviceWorker.getRegistration().then((registration)=>{if(registration.scriptURL!=='/service-worker.jsv=1.0.0'){registration.update();}});通常我们会将ServiceWorker的版本号放在scriptURL中,这样就可以通过scriptURL来判断ServiceWorker的版本了。

上面说到了ServiceWorker的更新,我们的缓存也是需要更新的,比如我们的ServiceWorker更新了,那么我们的缓存也需要更新,这样才能保证我们正常的版本迭代。

缓存在上一章中,是使用了自定义的cacheName来进行缓存的,其实我们可以用版本号来进行缓存,和ServiceWorker保持一致,然后在更新的时候删除对应的缓存:

//更新ServiceWorkernavigator.serviceWorker.getRegistration().then((registration)=>{if(registration.scriptURL!=='/service-worker.jsv=1.0.0'){registration.update();//删除缓存caches.delete('v1.0.0');}});上面的代码中,我们在更新ServiceWorker的时候,也删除了缓存,这样就可以保证我们的缓存和ServiceWorker的版本一致了。

本章几乎探索完了ServiceWorker的高频常用知识,以目前了解的ServiceWorker的知识来说,本章的内容已经足够满足大部分的需求了;

当然这只是一个起点,ServiceWorker的知识还有很多,而且并不是只围绕着ServiceWorker来讲,还有很多周边的知识;

例如本章讲到的showNotification方法,其实是Notification的API,push方法,其实是Push的API,还有很多;

THE END
1.WxPusher微信推送服务用户可以通过二维码或者链接关注这个应用,关注我们会把用户的UID回调给你指定的服务器,你可以通过UID给这个用户发送信息。 主题(Topic) 主题(Topic)是应用下面,一类消息的集合,比如创建了一个优惠相关的应用,用来给用户推送各种优惠信息,但是不同的用户关注的优惠信息不同,一部分人关注淘宝的,一部分人关注京东的。这种https://wxpusher.dingliqc.com/
2.什么是消息推送?鉴于Android 平台 C2DM 推送的不可用性,国内涌现出大量的第三方推送服务提供商.目前应用最为广泛的第三方推送服务提供商包括个推、极光、友盟、小米、华为、BAT 等,绝大部分 APP 都会优先考虑采用第三方推送服务。 2.自建推送服务 第三方服务在开发成本和消息到达率上表现都不错,但所有信息会经过第三方服务器,对于https://www.jianshu.com/p/4a5f07f6c02c
3.极光推送亿级消息推送专家,3 分钟快速接入,智能下发策略、精准后效分析,多平台多通道覆盖,有效提升用户活跃度和留存率。注册即享免费服务! 开通免费版高级版咨询技术文档Demo下载观看视频 您是否遇到了这些问题? 页面导航 应用场景繁杂 多个系统平台和厂商通道,平台和通道推送通知的规则多、更新快、兼容难、推送平台的升级维护https://www.jiguang.cn/push
4.消息推送平台UPush为开发者提供灵活、智能、有效的消息推送方案 ¥ 0 永久免费 立即免费使用 极简接入,精准推送 一键聚合多通道触达 支持多种消息类型 下发速度快,安全有保障 专业版 更高推送频次,提升数据统计查询能力和售后服务 ¥ 18000/年 DAU 1万以内 移动支付 阿里云支付 https://www.umeng.com/push
5.小米消息推送服务面向全网开发者,开放小米澎湃OS特色服务能力 了解详情 基于Android 15 Beta的 小米澎湃OS开发者预览版 现已发布 诚邀您开启适配旅程 了解详情 OneLink 统一链接 打破平台壁垒,线下场景跨平台分发 了解详情 开发 提供多形态的应用开发类型,共筑精彩的人车家全生态 https://dev.mi.com/console/appservice/push.html
6.OPPO开放平台OPPO 开放平台,为开发者提供强大的应用分发能力,丰富的应用服务及推广变现支持,助力开发者实现业务增长和商业变现。https://open.oppomobile.com/
7.推送服务·构建你的智能应用,使用蓝莺ChatAISDK推送服务是现代应用不可或缺的一部分,通过实现消息及时传递和通知用户,可以极大地提升用户体验。推送服务的核心包括:1、多平台支持;2、高效稳定的消息传递机制;3、个性化和定制化的推送内容;4、数据分析和反馈机制。其中,推送服务在多平台上的无缝集成至关重要。例如,蓝莺IM提供了企业级ChatAI SDK,使得开发者可以同时https://docs.lanyingim.com/wiki/push-services-41-20240626-1-20-1719332222.html
8.华为HarmonyOS灵活高效的消息推送服务(PushKit)通知消息通过Push Kit通道直接下发,可在终端设备的通知中心、锁屏、横幅等展示,用户点击后拉起应用。您可以通过设置通知消息样式来吸引用户。 开通权益 Push Kit根据消息内容,将通知消息分类为服务与通讯、资讯营销两大类别,开放通知消息自分类权益。 两种类型的通知消息在提醒方式、消息展示位置、推送数量上皆存在差异。https://blog.csdn.net/pisceshsu/article/details/142434263
9.推送服务(HMSCore)·GitBook推送服务(Push Kit)是华为提供的消息推送平台,建立了从云端到终端的消息推送通道。您通过集成推送服务,可以向客户端应用实时推送消息,构筑良好的用户关系,提升用户的感知度和活跃度。 推送服务现支持如下接入形态: Android:推送服务Android SDK为您的Android应用开发提供推送消息相关的接口,适用于手机和平板。主要包含根据https://service.cocos.com/document/zh/hms-push.html
10.PushKit推送服务系统通知推送软件消息推送华为开发者联盟提供稳定、及时、高效的消息推送服务,助力应用精准触达用户,有效提升用户活跃度和粘度。 支持平台 Android iOS Web Quick App HarmonyOS 查看文档体验Demo服务咨询 85000 全球接入应用 7亿 覆盖用户数 500亿 日消息发送量 功能介绍 多种推送样式 支持大文本、Inbox多行文本、带按钮等样式,帮助您更好的提高消息对用户https://developer.huawei.com/consumer/cn/hms/huawei-pushkit/
11.消息推送服务系统信息总览 名称:消息推送服务 版本:v0.4.10 源码:https://github.com/songquanpeng/message-pusher 启动时间:2024-01-30 17:31:12 自从上次启动已发送消息数目:2078 自从上次启动新注册用户数目:1 系统配置 系统配置总览 邮箱验证:未启用 GitHub 身份验证:未启用 https://www.infect-media.com/
12.多平台消息推送服务的实践多平台消息推送服务的实践 来源:转转技术 1 背景 1.1 强耦合的消息和业务代码 1.2 服务间代码重复,维护困难 1.3 消息发送的偶发丢失问题 2 现状和痛点 3 设计和实现 3.1 消息解耦的三元素 3.2 生命周期 3.3 限流 3.4 消息模版 4 总结 1 背景 随着各项业务线上化,触达用户的方式日益重要,而即时通讯服务成为了https://blog.itpub.net/70027824/viewspace-2999235/
13.消息推送服务消息推送服务 高到达率·安全稳定·便捷集成 立即接入 查看文档 业务介绍 消息推送服务面向广大开发者,通过在云端与客户端间建立 稳定可靠的长连接,帮助开发者向客户端推送 实时消息服务。荣耀致力于提供稳定、精准的消息推送服务,助力开发者 高效触达用户,提高应用曝光。 https://developer.hihonor.com/cn/promoteService
14.个推消息推送—Android和iOS推送SDK快速集成,免费使用个推作为业内首家支持统一推送接口标准的第三方消息推送服务商,能够为客户搭建符合统一推送标准(UPS)的智能触达体系,目前已为索尼、三星、坚果手机、海信通信、TCL、科大讯飞、零跑汽车等智能汽车制造商、汽车操作系统提供商、手机及电视厂商提供统一推送解决方案。 https://www.getui.com/notification-push
15.PUSH消息推送的实现原理第三方服务在开发成本和消息到达率上表现都不错,但所有信息会经过第三方服务器,对于信息敏感类 APP 而言,有必要考虑自建一套消息推送服务,能最大化保证安全,但自建推送服务需要对 App 客户端海量长连接的维护管理且面临保证 Push Service 常驻的难题等。 https://maimai.cn/article/detail?fid=1738578667&efid=sAfNRYxTRYuYTp7eA2CwWA
16.消息通知服务SMN消息提醒推送消息应用服务消息通知服务,支持10+协议消息推送,满足不同企业的个性化需求,包含邮件,短信,语音,HTTP/HTTPS,FunctionGraph函数、FunctionGraph工作流,企业微信群,钉钉群,飞书群,Welink群。 覆盖10+推送方式,满足多种场景推送 多通道告警事件通知 与云服务的集成 错峰流控 https://www.huaweicloud.com/product/smn.html
17.使用服务台推送消息谁能操作:服务台管理员 在推送中心,服务台管理员可以创建推送消息,定时定向推送给企业内部成员。如政策公告、故障通知、节日祝福、活动报名、销售战报等。? 二、操作流程? 进入服务台管理后台,点击 推送中心 > 创建推送 进入创建推送页面。 ? https://www.feishu.cn/hc/zh-CN/articles/360049067945
18.Pushdeer:开源多协议推送服务器,定制化推送解决方案在当今快速发展的信息时代,实时的消息、通知和数据推送变得至关重要。Pushdeer 软件应运而生,作为一款开源的推送服务器软件,它支持多种推送协议,为用户提供了灵活且可定制的推送解决方案。本文将深入介绍 Pushdeer 的功能特点、使用场景、安装部署以及简要的使用教程。 https://cloud.tencent.com/developer/article/2360079
19.Java服务端消息推送的实现小结java本文主要介绍了Java 服务端消息推送的实现小结,主要包括四种常见的消息实时推送方案:短轮询、长轮询、SSE 和 WebSocket,具有一定的参考价值,感兴趣的可以了解一下+ 目录 前言:当构建实时消息推送功能时,选择适合的方案对于开发高效的实时应用至关重要。消息的推送无非就推、拉两种数据模型。本文将介绍四种常见的消息实时https://www.jb51.net/program/300070ery.htm
20.为什么有的服务号每天可以推送消息给我?懂微信公众号运营的小伙伴都知道微信服务号每月只能推送四次消息,而每天都推送消息的服务号是通过接口实现,如果想要实现服务号每天推送消息,可以通过微号帮平台48小时信息推送功能实现,可以让服务号每天推送信息给互动活跃粉丝,但不能对全部粉丝推送,全部粉丝推送信息每月只有4次。互动活跃粉丝即在公众号里发信息、点击自https://www.weihaobang.com/jiaocheng/286.html
21..NETCoreSignalR:实现服务器实时消息推送通过SignalR,开发人员可以添加实时消息推送功能,以便服务器可以将消息实时推送给连接的客户端。 在Web应用中,实时通信已经成为了一个重要的功能需求。ASP.NET Core SignalR是一个ASP.NET Core库,它简化了向连接的客户端添加实时Web功能的过程。通过SignalR,开发人员可以添加实时消息推送功能,以便服务器可以将消息实时推https://www.51cto.com/article/785500.html
22.启点教育隐私政策使用目的/理由:提供消息推送服务 个人信息的种类:OAID、Android ID、IMSI、User ID、设备型号、Android版本、应用信息、设备归属地、网络相关信息、消息发送结果、通知栏状态、锁屏状态 第三方名称:广东欢太科技有限公司 第三方隐私政策或官网:https://open.oppomobile.com/new/developmentDoc/info?id=10288 https://www.gongfubb.com/legal/zjd/privacy.htm