在多源网站中构建渐进式 Web 应用时面临的挑战和解决方法。
发布时间:2019 年 8 月 19 日
过去,使用多源架构有一些优势。 对于渐进式 Web 应用,这种方法会带来许多挑战。特别是,同源政策对共享 Service Worker 和缓存、权限以及在多个来源之间实现独立体验施加了限制。
了解多源的优缺点,并说明在多源网站中构建渐进式 Web 应用的挑战和解决方法。
多个源的正确和错误使用方式
网站采用多源架构有几个正当理由,主要与提供一组独立的 Web 应用或打造彼此完全隔离的体验有关。此外,还有一些应避免的使用情形。
良好
首先,请查看以下实用原因:
本地化/语言:使用国家/地区代码顶级域名来区分在不同国家/地区投放的网站(例如
https://www.google.com.ar),或使用子网域来划分定位到不同地理位置的网站(例如:https://newyork.craigslist.org)或提供特定语言的内容(例如https://en.wikipedia.org)。独立 Web 应用:使用不同的子网域提供与主源网站用途大不相同的体验。例如,在新闻网站中,填字游戏 Web 应用可以有意从
https://crosswords.example.com提供,并作为独立的 PWA 安装和使用,而无需与主网站共享任何资源或功能。
缺点
如果您不打算执行上述任何操作,那么在构建渐进式 Web 应用时,使用多源架构可能会带来不利影响。
尽管如此,许多网站仍继续采用这种结构,原因不明或出于“历史遗留”原因。例如,使用子网域随意分隔本应属于统一体验的网站部分。
例如,强烈建议不要使用以下模式:
网站版块:在子网域上分隔网站的不同版块。在新闻网站中,首页通常位于
https://www.example.com,而体育版块位于https://sports.example.com,政治版块位于https://politics.example.com,依此类推。以电子商务网站为例,可以使用https://category.example.com表示商品类别,使用https://product.example.com表示商品页面,等等。用户体验流程:另一种不建议的做法是将网站的不同较小部分(例如子网域中的登录或购买流程页面)分开。例如,使用
https://login.example.com和https://checkout.example.com。
对于无法迁移到单一源的情况,下面列出了在构建渐进式 Web 应用时可能遇到的挑战以及可考虑的解决方法(如果可能)。
跨不同源的 PWA 面临的挑战和解决方法
在多个源上构建网站时,提供统一的 PWA 体验具有挑战性,这主要是因为同源政策施加了许多限制。我们来逐一了解。
Service Worker
Service Worker 脚本网址的来源必须与调用 register() 的网页的来源相同。例如,https://www.example.com 处的网页无法使用 https://section.example.com 处的 Service Worker 网址调用 register()。
另一个需要考虑的因素是,Service Worker 只能控制托管在其所属来源和路径下的页面。这意味着,如果 Service Worker 托管在 https://www.example.com,则它只能控制来自该源站的网址(根据范围参数中定义的路径),而无法控制其他子网域中的任何网页,例如 https://section.example.com 中的网页。
在这种情况下,唯一的解决方法是使用多个 Service Worker(每个源一个)。
缓存
Cache 对象、indexedDB 和 localStorage 也仅限于单个源。这意味着,无法从 https://www.section.example.com 等位置访问属于 https://www.example.com 的缓存。
在这种情况下,您可以采取以下措施来妥善管理缓存:
利用浏览器缓存:始终建议使用传统的浏览器缓存最佳实践。这种方法还有一个额外的好处,那就是可以跨源重复使用缓存的资源,而 Service Worker 的缓存无法做到这一点。如需了解如何将 HTTP 缓存与 Service Worker 搭配使用的最佳实践,请参阅此博文。
确保 Service Worker 安装过程轻量化:如果您维护多个 Service Worker,请避免让用户在每次导航到新源时都承担高昂的安装成本。换句话说:仅预缓存绝对必要的资源。
权限
权限也限定于源。这意味着,如果用户向源 https://section.example.com 授予了特定权限,该权限不会沿用到其他源(例如 https://www.example.com)。
由于无法跨源共享权限,因此唯一的解决方案是在需要特定功能(例如位置信息)的每个子网域上请求权限。对于网络推送等功能,您可以维护一个 Cookie,以跟踪用户是否已在其他子网域中接受该权限,从而避免再次请求该权限。
安装
如需安装 PWA,每个源都必须有自己的清单,其中包含相对于自身的 start_url。这意味着,在给定源(例如 https://section.example.com)上收到安装提示的用户将无法在其他源(例如 https://www.example.com)上安装具有 start_url 的 PWA。
换句话说,在子网域中收到安装提示的用户只能安装子页面的 PWA,而不能安装应用主网址的 PWA。
此外,如果每个子网域都符合安装条件,并提示用户安装 PWA,那么同一用户在浏览网站时可能会收到多个安装提示。
为缓解此问题,您可以确保仅在主源上显示提示。当用户访问符合安装条件的子网域时:
- 监听
beforeinstallprompt事件。 - 阻止提示出现,调用
event.preventDefault()。
这样,您就可以确保提示不会显示在网站的非预期部分,同时可以继续在主源(例如首页)中显示提示。
独立模式
在独立窗口中浏览时,如果用户移出 PWA 清单设置的范围,浏览器的行为会有所不同。具体行为取决于每个浏览器版本和供应商。例如,在最新版 Chrome 中,当用户在独立模式下移出范围时,系统会打开一个 Chrome 自定义标签页。
在大多数情况下,此问题无法解决,但对于在子网域中托管的一小部分体验(例如登录工作流),可以采用一种权宜解决方法:
- 新网址
https://login.example.com可以在全屏 iframe 中打开。 - 在 iframe 内完成任务(例如登录流程)后,可以使用 postMessage() 将任何结果信息从 iframe 传回父级页面。
- 最后一步,主页面收到消息后,可以取消注册监听器,并最终从 DOM 中移除 iframe。
总结
同源政策对基于多个源构建、希望实现连贯 PWA 体验的网站施加了许多限制。因此,为了向用户提供最佳体验,我们强烈建议您不要将网站划分为不同的源。
对于已经以这种方式构建的现有网站,要让多源 PWA 正常运行可能具有挑战性,但我们已经探索了一些潜在的解决方法。每种方法都有其优缺点,因此请自行判断在网站上采用哪种方法。
在评估长期策略或网站重新设计时,请考虑迁移到单一源站,除非有重要原因需要保留多源站架构。
衷心感谢以下人员的技术审核和建议:Penny Mclachlan、Paul Covell、Dominick Ng、Alberto Medina、Pete LePage、Joe Medley、Cheney Tsai、Martin Schierle 和 Andre Bandarra。