”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 Deno 发送 Web 推送消息

使用 Deno 发送 Web 推送消息

发布于2024-08-01
浏览:680

Send Web Push messages with Deno

最近,我一直在开发一个仅使用 Web API 从头开始​​构建的新 webpush 包。这使得(至少在理论上)直接从浏览器发送 Web Push 消息成为可能。

这篇博文旨在解释什么是 Web Push 协议,它是如何工作的
(RFC 8291) 以及如何使用我的库发送 Web 推送消息。

什么是网络推送协议?

Web 推送协议是一种中间协议,允许应用程序向用户代理(通常是浏览器)发送消息。

它与服务器发送事件(SSE)类似,消息被推送到用户代理,但它有不同的目的。 Web 推送消息不需要网站作为服务工作者打开一个选项卡
可以监听推送消息。它在后台运行。

Web 推送协议如何工作?

Web Push 协议涉及三个参与者:

  • 用户代理:通常是您的网站访问者浏览器
  • 推送服务:由 Google、Mozilla 或 Apple 维护和拥有的推送服务器,具体取决于浏览器
  • 应用程序服务器:您的服务器

以下是它们之间交互的概述:

     -------             --------------         ------------- 
    |  UA   |           | Push Service |       | Application |
     -------             --------------         ------------- 
        |                      |                      |
        |        Setup         |                      |
        ||                      |
        |           Provide Subscription              |
        |-------------------------------------------->|
        |                      |                      |
        :                      :                      :
        |                      |     Push Message     |
        |    Push Message      |



由于多种原因需要中间推送服务。

首先,它减少了带宽和电池使用量,因为用户代理仅为所有网站维护一个连接,而不是每个网站一个连接。

它还提高了可扩展性和可靠性,因为主要浏览器的推送服务旨在处理数百万用户。由于如果用户代理离线,则必须保留推送消息,因此构建推送服务需要大量工程、弹性且冗余的基础设施

最后,对于小型网络公司来说,构建、部署和维护自定义推送服务通常过于复杂且耗费资源。这会给大公司带来不公平的竞争优势,因为他们将拥有必要的资源来开发和完善自己的推送服务。

如果您是像我一样关注隐私的用户,请参阅中介服务
接收所有消息都会引发危险信号。为了解决这个问题,Web Push
消息通过 HTTP 加密内容编码进行保护(请参阅我的
http-ece 包),确保
敏感信息仍然受到保护,任何第三方都无法读取
过境服务。

设置

您可能已经注意到设置箭头与上面 ASCII 图中的其他箭头不同。这是因为设置阶段依赖于实现。所有主流浏览器都实现了 javascript

中推送 API 不同的方式。返回标准
的 PushManager.subscribe() 方法 PushSubscription 已公开。

订阅始终包含与推送订阅关联的唯一 URL 端点以及用于加密消息的公钥。

创建订阅时,可以提供可选的applicationServerKey来标识应用服务器推送消息。这是自愿应用程序服务器标识 (VAPID) 身份验证方法
(RFC 8292)。 VAPID 密钥用于减轻对推送服务的 DDOS 攻击。此外,在应用程序服务器和推送服务之间添加身份验证可以降低泄露订阅端点的风险。由于这些原因,它们在 Firefox 中是强制性的。

提供订阅

第二步是将订阅发送到应用程序服务器,以便它可以开始发送消息。

应用程序服务器通常会将订阅存储在数据库中以供以后重用。

推送消息

最后,为了推送消息,应用程序服务器使用 vapid 身份验证方案发送加密的 HTTP 请求,前提是提供了 applicationServerKey 来创建订阅。

如果推送服务收到消息时用户代理在线,则
转发。否则,它将被存储,直到用户代理上线或消息过期。

当用户代理收到消息时,它会执行主要用于显示通知的推送事件处理程序。

使用 webpush 设置应用程序服务器

首先,您必须生成 VAPID 密钥,因为某些浏览器强制要求它们:

$ deno run https://raw.githubusercontent.com/negrel/webpush/master/cmd/generate-vapid-keys.ts

复制输出并将其保存到文件中,您不需要再次生成 VAPID 密钥。

在您的应用程序服务器代码中,您可以按如下方式加载它们:

import * as webpush from "jsr:@negrel/webpush";

// Read generated VAPID file.
const vapidKeysJson = Deno.readTextFileSync("./path/to/vapid.json");

// Import VAPID keys.
webpush.importVapidKeys(JSON.parse(vapidKeysJson));

然后,您需要创建一个ApplicationServer对象实例。

// adminEmail is used by Push services maintainer to contact you in case there
// is problem with your application server.
const adminEmail = "[email protected]";

// Create an application server object.
const appServer = await webpush.ApplicationServer.new({
  contactInformation: "mailto:"   adminEmail,
  vapidKeys,
});

然后要发送推送消息,只需创建一个 PushSubscriber 并调用它的
pushMessage()/pushTextMessage()方法如下:

const subsribers = [];

// HTTP handler for user agent sending their subscription.
function subscribeHandler(req) {
  // Extract subscription send by user agent.
  const subscription = await req.json();

  // Store subscription in db.
  // ...

  // Create a subscriber object.
  const sub = appServer.subscribe(subscription);

  // Store subscriber in memory.
  subscribers.push(sub);
}

// Helper method to send message to all subscribers.
function broadcastMessage(msg) {
  for (const sub of subscribes) {
    sub.pushTextMessage(msg, {});
  }
}

就是这样,您向订阅者发送推送消息!

webpush 存储库包含一个交互式示例,其中包含可以在本地运行的类似代码。它还包含客户端 JavaScript 代码,所以一定要检查一下!

版本声明 本文转载于:https://dev.to/negrel/send-web-push-messages-with-deno-1kcl?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
    为有效的slug生成首先,该函数用指定的分隔符替换所有非字母或数字字符。此步骤可确保slug遵守URL惯例。随后,它采用ICONV函数将文本简化为us-ascii兼容格式,从而允许更广泛的字符集合兼容性。接下来,该函数使用正则表达式删除了不需要的字符,例如特殊字符和空格。此步骤可确保slug仅包含...
    编程 发布于2025-04-01
  • 如何同步迭代并从PHP中的两个等级阵列打印值?
    如何同步迭代并从PHP中的两个等级阵列打印值?
    同步的迭代和打印值来自相同大小的两个数组使用两个数组相等大小的selectbox时,一个包含country代码的数组,另一个包含乡村代码,另一个包含其相应名称的数组,可能会因不当提供了exply for for for the uncore for the forsion for for ytry...
    编程 发布于2025-04-01
  • 如何使用node-mysql在单个查询中执行多个SQL语句?
    如何使用node-mysql在单个查询中执行多个SQL语句?
    Multi-Statement Query Support in Node-MySQLIn Node.js, the question arises when executing multiple SQL statements in a single query using the node-mys...
    编程 发布于2025-04-01
  • 如何解决由于Android的内容安全策略而拒绝加载脚本... \”错误?
    如何解决由于Android的内容安全策略而拒绝加载脚本... \”错误?
    Unveiling the Mystery: Content Security Policy Directive ErrorsEncountering the enigmatic error "Refused to load the script..." when deployi...
    编程 发布于2025-04-01
  • 如何使用Regex在PHP中有效地提取括号内的文本
    如何使用Regex在PHP中有效地提取括号内的文本
    php:在括号内提取文本在处理括号内的文本时,找到最有效的解决方案是必不可少的。一种方法是利用PHP的字符串操作函数,如下所示: 作为替代 $ text ='忽略除此之外的一切(text)'; preg_match('#((。 &&& [Regex使用模式来搜索特...
    编程 发布于2025-04-01
  • 如何实时捕获和流媒体以进行聊天机器人命令执行?
    如何实时捕获和流媒体以进行聊天机器人命令执行?
    在开发能够执行命令的chatbots的领域中,实时从命令执行实时捕获Stdout,一个常见的需求是能够检索和显示标准输出(stdout)在cath cath cant cant cant cant cant cant cant cant interfaces in Chate cant inter...
    编程 发布于2025-04-01
  • 在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    在Ubuntu/linux上安装mysql-python时,如何修复\“ mysql_config \”错误?
    mysql-python安装错误:“ mysql_config找不到”“ 由于缺少MySQL开发库而出现此错误。解决此问题,建议在Ubuntu上使用该分发的存储库。使用以下命令安装Python-MysqldB: sudo apt-get安装python-mysqldb sudo pip in...
    编程 发布于2025-04-01
  • 为什么我会收到MySQL错误#1089:错误的前缀密钥?
    为什么我会收到MySQL错误#1089:错误的前缀密钥?
    mySQL错误#1089:错误的前缀键错误descript [#1089-不正确的前缀键在尝试在表中创建一个prefix键时会出现。前缀键旨在索引字符串列的特定前缀长度长度,可以更快地搜索这些前缀。了解prefix keys `这将在整个Movie_ID列上创建标准主键。主密钥对于唯一识别...
    编程 发布于2025-04-01
  • 您如何在Laravel Blade模板中定义变量?
    您如何在Laravel Blade模板中定义变量?
    在Laravel Blade模板中使用Elegance 在blade模板中如何分配变量对于存储以后使用的数据至关重要。在使用“ {{}}”分配变量的同时,它可能并不总是最优雅的解决方案。幸运的是,Blade通过@php Directive提供了更优雅的方法: $ old_section =“...
    编程 发布于2025-04-01
  • 如何有效地选择熊猫数据框中的列?
    如何有效地选择熊猫数据框中的列?
    在处理数据操作任务时,在Pandas DataFrames 中选择列时,选择特定列的必要条件是必要的。在Pandas中,选择列的各种选项。选项1:使用列名 如果已知列索引,请使用ILOC函数选择它们。请注意,python索引基于零。 df1 = df.iloc [:,0:2]#使用索引0和1 的 ...
    编程 发布于2025-04-01
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-04-01
  • 为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    使用php dateTime修改月份:发现预期的行为在使用PHP的DateTime类时,添加或减去几个月可能并不总是会产生预期的结果。正如文档所警告的那样,“当心”这些操作的“不像看起来那样直观。 考虑文档中给出的示例:这是内部发生的事情: 现在在3月3日添加另一个月,因为2月在2001年只有2...
    编程 发布于2025-04-01
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    将pandas dataframe列转换为dateTime格式示例:使用column(mycol)包含以下格式的以下dataframe,以自定义格式:})指定的格式参数匹配给定的字符串格式。转换后,MyCol列现在将包含DateTime对象。 date date filtering > = p...
    编程 发布于2025-04-01
  • 如何干净地删除匿名JavaScript事件处理程序?
    如何干净地删除匿名JavaScript事件处理程序?
    删除匿名事件侦听器将匿名事件侦听器添加到元素中会提供灵活性和简单性,但是当要删除它们时,可以构成挑战,而无需替换元素本身就可以替换一个问题。 element? element.addeventlistener(event,function(){/在这里工作/},false); 要解决此问题,请考虑...
    编程 发布于2025-04-01
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-04-01

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3