前言 本文是关于 Mozilla 内 Web 推送服务和 Web Push 使用方法的系列文章之一。作者的用意并非提供一般性的指引,而是对 Web Push 提供最佳使用方法和建议,并设定读者对于 JavaScript、Python 或其他相关技术有一定的了解。
Web Push 上的一大挑战是要找出问题点(bug)。Web Push 有大量的「可动部件」、系统和组件,所有的元素都必须彼此合作,才能成功完成信息的推送和接收。虽然这篇文章无法一一说明导致推送通知失败的原因,但会针对常见的问题提供实用的工具和建议。
常见问题
错误回报 最大的问题源自于网站忽略提供的return codes。不久前在 另一篇文章中曾建议,可通过订阅服务减少发送失败信息的成本。花点心思留意系统传回的状态代码也是很重要的。
譬如,错误信息的正文(body)可能是这样: { ‘errno’: 102, ‘message’: ‘Requestdid not validate invalid token’, ‘code’: 404, ‘error’: ‘NotFound’ }
你可在 Autopush 文档中找到错误值的清单(Autopush 是用来执行接收和转寄推送订阅更新的开源服务器的名称)。因为 Autopush 服务器会尽可能提供详细和有用的数据,所以,如果有通知发不出去,Autopush的信息应该会很有帮助。
VAPID 的问题 另一个潜在问题点则与 VAPID 有关。VAPID 是能让提供订阅服务的网站「表明身份」的新兴标准,也就是说,当重大问题发生时,推送服务的服务器运营者便有办法联系到问题通知的来源。假使你看到大量带有 401 状态代码的响应消息,十之八九是因为 VAPID 验证出了差错。
VAPID 还能让网站设定「 限制性订阅」。此做法能把订阅锁住,只允许拥有 VAPID 密钥的人发送订阅通知。这其中的原理有点复杂。
但简单来说,VAPID 是以密钥密码签署的数据区块。此密钥有两个部分,其一是用以签署 VAPID 代码(token)、绝对不能分享给他人的私钥;其二则是负责制作限制性订阅、可透露给他人的公钥。一般来说,VAPID 密钥可以维持一段时间不变——约一年左右,但绝不能万年不变。稍后会进一步说明。
当你的应用程序 提出推送端点请求时,你可以选择把 VAPID 的公钥当作应用服务器密钥(applicationServerKey)来提供。这会产生一个只有该密钥能开启的新订阅端点。若要成功发送订阅请求,你必须以相应的私钥来签署 VAPID 区块,并在请求中包含公钥(在请求内加入公钥的方式会因 Draft 01 及 Draft 02 而 有区别。你或许需要能辅助授权签署的 数据库,也不妨先参考推送服务的文档,了解一下其所接受的格式。大多数的推送平台都接受 Draft 02)。
请注意,VAPID 公钥会跟你请求的 URL 绑在一起,也就是说,之后每当你想送数据给该 URL,都必须使用同样的密钥组合。假如你想换 VAPID 密钥,就得先取得新端点后再删除旧的。当然你有权决定如何处理。你的 app 可以从已知的地址取得新的公钥,产生新的 URL 请求后,再把新的注册信息传回给服务器。这会使用到你在 pushsubscriptionchange 事件上会用的大部分的程序代码。
出现 VAPID 401 错误时,你应该确认以下三点: - 你是不是用同样的密钥组合来存取限制性订阅的内容?
- 你是否已正确签署 VAPID 授权密钥?
- 你的请求是否涵盖了所有必要的VAPID 标头?
数据加密 推送信息的加密方法也有可能造成推送失败。不过,由于推送服务器在接受信息时,根本无从判断信息是否正确加密,也使得这成为最难排错的问题。还有,用户代理程序(User Agent,UA)只会递送它能成功解密的信息。这能避免应用程序因收到大量错误信息而吃掉手机电池太多的电量。
同样的,解决这类问题最有效的办法是使用 数据库。不过,数据库也不是万灵丹,在某些状况下,你恐怕还是得自己动手做。 这个网页提供了数据加密的步骤,不过,目前只有 Firefox 支持此机制。
请留意,Push Service有部分新规则仍未获得普遍支持。至规则发布之际,大多的推送平台都将接受 ECE Draft 03(aesgcm)编码。虽然已有人 提议 UA 应回传其所支持的密码形态,但该提案尚未获得正式采纳。不过,这就是使用尚在发展中的技术会出现的问题。如果你想要掌握最新的规则提案,你可关注Push Service 的工作小组。
可惜的是,因为 PushService 无法解密信息,所以难以侦测到许多的加密错误。幸运的是,我们可以“窥视”客户端,判断其中是否有bug。
为桌面系统排错
这样的好处是,你可以看到你的server worker 的日志,也能看到其他的推送通知。譬如,下面是一个测试页,你或许能看到一些和你的浏览器相似的东西:
(上图:浏览器控制台输出信息的范例)
在窗口下方有四个来自“sw.js” 的信息。前三个是console.info() 信息,分别说明一个新通知已送达、该通知的内容是什么,以及相关的客户端为何。需要特别注意的是第四个信息—— console.error(),内容为「Service worker couldn’tsend message: Error: No valid client to send to」。当service worker 和其 parent 失去关联时,这种状况便可能发生。简单来说,这四个信息传达了一个好消息和一个坏消息:好消息是,推送的通知完好无缺地抵达了,但坏消息是,它无处可去。
另一个实用的资源是在 about:debugging#workers的「service worker debugging」页,里面提供了所有已注册的 service worker 脚本(script),让你取消注册、选择性地发送推送消息、并帮 service worker 脚本排错。你可在 Mozilla Hacks上找到 更多有关 about:debugging页的说明。
为Android 设备排错 帮 Android 设备的推送功能排错的方法也差不多。就像帮桌面端排错一样,你必须把 dom.push.debug 设为「true」,并把 dom.push.loglevel 设为「debug」。只不过,Android 不像桌面系统有浏览器控制台来让你轻松掌握所有信息。所有的通知都会被记录到 Android 的错误日志里,所以你可以通过 adb logcat 等指令来追踪错误的记录。有些开发人员也会使用 grep 来找有“Gecko(Push|Console)”的记录。
下面的画面虽然不太美观,但呈现出来的内容相差不大,其中也包括有助于锁定和解决程序错误的 service workers 的控制台信息。另外,值得一提的是,太长的信息可能会被adb 截短。
adb 记录的例子(原文画面可上下左右滚动,此处只是截图贴上):
从上图来看,可以从中得到更多的信息,包括 GCM 已收到信息并已传给 Gecko。为了节省空间,其中不少日志信息已被移除或缩短,但仍然可以辨别问题究竟是在你的app还是在网络中。
结论 使用 Push 的好处虽多,但千万别忘了,这技术毕竟还很新。有些东西可能会变,有些问题也要小心提防。欢迎与我们分享你碰到的程序错误(bug),并提供建议,帮助我们不断改进。若你有任何问题,也欢迎到 irc.mozilla.org 上提问(#push)。
|