朋也的博客 » 首页 » 文章

浏览器中serviceWorker用法

作者:朋也

日期:2019-05-27

类别:javascript学习笔记

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

上一篇博客介绍了PWA的用法,最后留了个serviceWorker用法没有说,这一篇来介绍一下

先上图

先说一下流程:生成公/私钥 -> 浏览器中使用公钥注册服务 -> 服务端使用私钥推送 -> 浏览器中接收推送展示

流程图网上非常多,我这就不截图展示了

生成密钥

我这使用nodejs语言来实现,其它语言版本也有,不过没有nodejs用起来方便

创建一个文件夹 push-demo 在文件夹内安装 web-push 包依赖,然后创建一个 test.js 加上下面代码,运行即可

const webpush = require("web-push");

// 生成公钥私钥

const vapidKeys = webpush.generateVAPIDKeys(); // 1.生成公私钥

console.log(vapidKeys);

结果如下

{ publicKey:

'BK_LXU7DEQ5rAfk8kCNsa-5E9ntYKUoBemBjO-ZaEjpK3PFKCzpUAfYqlk1p2wmbsNBnYSRALpyddMDhHuspPag',

privateKey: 'bC665pacSeHbHv9iY4H0106oUTJWTTyUAsbwEnXX1Mg' }

浏览器注册服务

有了公钥,就可以在浏览器里通过代码注册服务了,代码如下,注释都写好了,看一下就明白了

function urlB64ToUint8Array(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;

}

const publicKey =

"BK_LXU7DEQ5rAfk8kCNsa-5E9ntYKUoBemBjO-ZaEjpK3PFKCzpUAfYqlk1p2wmbsNBnYSRALpyddMDhHuspPag";

// 判断浏览器是否支持serviceWorker,支持的话,注册服务

if ("serviceWorker" in navigator) {

send().catch(err => console.error(err));

}

async function send() {

console.log("Registering service worker...");

// 这里要注册serviceWorker,要提前写一个js,(注意路径),后面接收推送就是在这个js里通过代码实现的

// 这个js创建好就可以了,暂时不需要写东西

navigator.serviceWorker.register("/sw.js").then(register => {

// 判断浏览器是否有推送服务支持

if (window.PushManager) {

register.pushManager.getSubscription().then(subscription => {

// 如果用户没有订阅

if (!subscription) {

// 调用浏览器api,提示用户是否开启网站推送服务

register.pushManager

.subscribe({

userVisibleOnly: true,

applicationServerKey: urlB64ToUint8Array(publicKey) // 密钥还要将其转换一下,否则会报错,转换的代码是固定的,我这里用的就是网上找的

})

.then(subscription => {

// 用户同意接收网站的消息推送,则发送一个请求跟服务端创建连接

fetch("/subscription", {

method: "post",

body: JSON.stringify(subscription),

headers: {

"content-type": "application/json"

}

});

})

.catch(err => console.log("用户没有同意开启通知...", err));

} else {

fetch("/subscription", {

method: "post",

body: JSON.stringify(subscription),

headers: {

"content-type": "application/json"

}

});

console.log("You have subscribed our notification");

}

});

}

});

}

服务端响应

如果浏览器端用户同意了接收推送服务的功能,然后发起了一个跟服务器保持连接的请求,服务端要做相应的处理,将传过来的数据持久化,后面发送推送要用到

浏览器如果同意,然后发送一个连接的请求,传给服务端的数据长这个样

如果是Chrome浏览器,则长下面这个样

{

endpoint:

"https://fcm.googleapis.com/fcm/send/cZdEewi209A:APA91bGo9U4c9ycxJkeIGRlpR-sl0eKafNvtLSVJd_kW--IDe7LY-N-YCsVqC4oLBE1DEKD6JHvVMuNxFq3ANgw9orH1Eo3-JLTRodNyYYn-5Xzz0IM80cfBFuDXWby8gdVudLMb96_j",

expirationTime: null,

keys: {

p256dh:

"BGMG0WgSZueddroRLDxxwFezTTtgby1tT7mJnTv-BDynkTAo_hjroyTfuWa6zbpr6R9xkqPt-rN3mvZnIPwMwpk",

auth: "wWYPAHPDCnAE8y6oTPWj-w"

}

}

如果是firefox浏览器则长下面这个样

{

endpoint:

"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABc57EZB3ZRqMvOUXfFkXY_CXowfxF45Kr76pyMPTeA6vCgEBWieKYC2dwoqsXRkibhavFh9xJwK1llZwnDfCzGIEiMJxFMgQcHp69meonmL1Wlu8ij_MTwlsf54Y-die8D9wIpMjkjnl9wiWVezcapOFBSRzbBA_nfwUtHpkTBG1w6iXs",

keys: {

auth: "4kTmhdWGaWLoZReISaXj1w",

p256dh:

"BKadOZ_MoS_GTdtYMhuCdWoO5S_gcerg71dD-Pk0YpHXpzyD5JKLS9FsWPhPXWgB1Ca0H74cRsUlufruMNzc5Mo"

}

}

我这里是将其入库,有推送的时候,直接查询然后调用推送方法直接推送消息

exports.subscription = async (ctx) => {

// 获取user-agent用于判断浏览器

const user_agent = ctx.headers['user-agent'];

// 获取订阅的信息,入库时将其转成字符串保存即可

const subscription = ctx.request.body;

const user = ctx.session.user;

let chrome_subscription, firefox_subscription;

if (user_agent.indexOf('Chrome') > -1) chrome_subscription = subscription;

if (user_agent.indexOf('Firefox') > -1) firefox_subscription = subscription;

await user_service.update_user_subscription_by_id(

user.id,

JSON.stringify(chrome_subscription),

JSON.stringify(firefox_subscription)

);

ctx.response.status = 201;

ctx.body = {};

};

发送推送

众所周知,国内google的服务是请求不通的,所以我这用firefox的推送服务来演示

首先在上面注册时写的sw.js文件里实现接收推送消息的代码

// 接收推送消息事件

self.addEventListener("push", function (event) {

console.log("[Service Worker] Push Received.");

console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

let notificationData = event.data.json();

// 弹消息框

event.waitUntil(

self.registration.showNotification(notificationData.title, notificationData)

);

});

// 通知被点击了的事件,比如打开一个链接之类的

self.addEventListener("notificationclick", function (event) {

console.log("[Service Worker] Notification click Received.");

let notification = event.notification;

notification.close();

// event.waitUntil(self.clients.openWindow(notification.action));

// This looks to see if the current is already open and

// focuses if it is

event.waitUntil(

self.clients

.matchAll({

type: "window"

})

.then(function (clientList) {

for (let i = 0; i < clientList.length; i++) {

let client = clientList[i];

if (client.notification.url === "/" && "focus" in client) {

// return client.focus();

return self.clients.openWindow(client.notification.url);

}

}

if (self.clients.openWindow && notification.data.url) {

return self.clients.openWindow(notification.data.url);

}

})

);

});

服务端推送消息

const webpush = require("web-push");

let publicKey = 'BK_LXU7DEQ5rAfk8kCNsa-5E9ntYKUoBemBjO-ZaEjpK3PFKCzpUAfYqlk1p2wmbsNBnYSRALpyddMDhHuspPag';

let privateKey = 'bC665pacSeHbHv9iY4H0106oUTJWTTyUAsbwEnXX1Mg';

webpush.setVapidDetails(

"mailto:py2qiuse@gmail.com",

publicKey,

privateKey

);

const firefoxSubscription = {

endpoint:

'https://updates.push.services.mozilla.com/wpush/v2/gAAAAABc61hnBVOJZIOLZgSN7x8Pom_AKoVvE4yAaCi0wnWaXv05FAVGx2tlMSPAkKCaj_DnYDzmyWRJGwofpuYuXDiDPX2RSNUmTiXfgTP55t9c82UzFdeZvvkvqr2vdD-H1QIfIGd3LJzh58Pd6SRey2su91F160ilKsz_3AOzGAEv_FloXeY',

keys:

{

auth: '9-beSGAEs_f5JM4Dkit-vw',

p256dh:

'BEfxlwj1XLIEBWFa-Bc7TS2aMQLcJK9H0mSbl5OSkN1vFPAEJJZRfeHDpz09JDUx6QhA9YG7Wjm7d7dXq10ixQ4'

}

};

// push的数据

const payload = {

title: "测试推送",

body: "推送内容,一串链接,点击打开",

icon: "https://yiiu.co/favicon.ico",

data: {url: "https://tomoya92.github.io/pybbs/", text: 'hello world'},

};

// 发送通知

webpush.sendNotification(firefoxSubscription, JSON.stringify(payload));

运行代码,firefox上就可以收到一条推送消息了

补充:payload的数据格式这见个是固定的,如果你想自定义一些数据,可以写在data对象里,在sw.js里点击事件里可以获取到,然后做相应的处理

sw.js里的点击通知事件回调参数里有一个 notification 对象,这个对象就是在 接收通知事件里打开通知的方法中传入的第二个参数对象,如果传的是服务端推送的消息对象,那也就是payload对象,可以直接拿data中的url通过调用 openWindow()方法打开这个链接

不得不说,还是chrome方便,可以直接对sw.js里的代码进行调试,在firefox上开发调试真心麻烦 。。。

worker服务器推送消息,浏览器中serviceWorker用法相关推荐

  1. worker服务器推送消息,关于Worker如何向指定Client推送消息

    use Workerman\Worker; require_once './Workerman/Autoloader.php'; // 初始化一个worker容器,监听1234端口 $worker = ...

  2. 服务器推送消息方法总结及实现(java)

    服务器推送消息方法总结及实现(java) 最近在进行web开发时,有用到服务端推送消息这个功能,相信大家在平常开发时,也经常会有这种需求.本文对常用的几种服务器推送消息方法进行整理和总结,并实现使用流 ...

  3. html5服务器推送消息的各种解决办法,WEB服务器推送消息的各种解决办法

    前言:在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知.而BS架构本身存在的问题就是,服务器一直采用的是一问一答的机制.这就意味着如果 ...

  4. HTTP Websocket 服务器推送消息

    文章目录 HTTP HTTP请求过程 1. 无状态 2. 基于TCP协议 心跳包 3. 长.短连接 4. 单向请求 传统服务器推送技术 短轮询 polling 同源限制 跨域资源共享 长轮询 long ...

  5. asp服务器推送消息,asp.net实时向客户端推送消息(SignalRWeb)

    [实例简介]ASP.net中服务器端向客户端推送消息,多用于在线聊天 [实例截图] [核心代码] using System; using System.Collections.Generic; usi ...

  6. java服务器推送消息技术

    其实有很多种方式实现服务器推送,它们各有各的优缺点: 1.传统轮询:此方法是利用 HTML 里面 meta 标签的刷新功能,在一定时间间隔后进行页面的转载,以此循环往复.它的最大缺点就是页面刷性给人带 ...

  7. netty多台服务器 推送消息,基于Netty的消息推送服务器集群设计与实现

    徐龙光 何顶新 摘 要:消息推送是当前移动应用中十分必要的一项技术,服务者需要使用消息推送以保持用户活跃度,提高应用存留率.为了满足消息推送的需求和增强推送系统的性能,采用Netty网络编程框架并搭建 ...

  8. Android Notification实现推送消息过程中接受到消息端有声音及震动及亮屏提示

    在Android Notification状态栏通知一文中,简单实现了消息的推送效果,这里就接着上文说一下,当用户接受到消息时的提示效果 // 5-加入震动及声音及亮屏 notification.de ...

  9. 手机 服务器 推送消息推送消息,推送信息到手机的pushover使用方法及sample code

    今天给大家介绍一个好东西,用了两年多了,一直没时间给大家推荐.pushover,移动端的信息推送服务API,包括使用.设置以及API实现. 用途 在关键节点放上推送(比如用户注册.举报.评论,系统检测 ...

最新文章

  1. Ubuntu安装Beyond-Compare 4
  2. (用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正...
  3. (2006, 'MySQL server has gone away') 错误解决 - dba007的空间 - 51CTO技术博客
  4. beta book读书俱乐部的构思
  5. Memcached原理深度分析详解
  6. 笔记6 | 从源码理解分析mScrollX和mScrollY,scrollTo()和scrollBy(),smoothScrollTo和smoothScrollBy...
  7. [蓝桥杯]最大连续子序列和
  8. 【亲测】二极管电压测试“跳坑”注意事项——硬件的板载测试验证
  9. 细数Android开发者的艰辛历程,全网最新
  10. python快速排序代码_Python实现快速排序算法
  11. 民意调查Django实现(一)
  12. Java 核心五个类(File、Outputstream、Inputstream、Reader、Writer)一个接口(Serializable)...
  13. 中国联通与小米深度联动 联合推出Wi-Fi 6路由器AX3600
  14. free释放链表节点崩溃_【链表6】lt;最新gt;初识链表(link list)
  15. 昔日的 HTC 与三星,今日的苹果:寒冬过后手机厂商才会明白的潜规则
  16. VS2008下改变项目的默认属性
  17. 物联网可视化平台-场景编辑器-轻松实现三维地图搭建
  18. CnPack应用总结
  19. qq游戏大厅+android,手机QQ游戏大厅Android客户端体验
  20. Java初学笔记30-【MiniQQ聊天部分代码】

热门文章

  1. 2021年电工(中级)免费试题及电工(中级)模拟考试题库
  2. 从头开始学算法:考研机试题练习(C/C++)–STL使用
  3. python3去掉空格_python如何去掉空格
  4. 神经网络训练过程中出现loss为nan,神经元坏死
  5. python专业版与社区版的区别_pycharm专业版和社区版区别
  6. 少说话多写代码之Python学习010——字典的简单使用
  7. Vue框架基本页面的使用模板
  8. 万字长文带你吃透Spring是怎样解决循环依赖的
  9. 报名照片太大怎么压缩?压缩图片到固定大小的方法
  10. 【电力电子技术速通】六、逆变电路(一)电压型与电流型逆变电路