在多源网站中构建渐进式 Web 应用时遇到的挑战和权宜解决方法。
背景
过去,使用多源架构有一些优势,但对于渐进式 Web 应用,这种方法会带来诸多挑战。具体而言,同源政策会对共享服务工件和缓存、权限以及在多个源中实现独立体验等方面施加限制。本文将介绍使用多个源的好处和弊端,并说明在多源网站中构建渐进式 Web 应用时会遇到的挑战和权宜解决方法。
使用多个来源的正确做法和错误做法
网站采用多源架构的原因有很多,但大多数都与提供一组独立的 Web 应用或打造完全隔离的体验有关。还有一些使用情形应避免。
良好
我们先来看看有用的原因:
本地化/语言:使用国家/地区代码顶级域名来区分要在不同国家/地区提供的网站(例如
https://www.google.com.ar
),或使用子网域来区分定位到不同地理位置的网站(例如:https://newyork.craigslist.org
)或提供特定语言的内容(例如https://en.wikipedia.org
)。独立的 Web 应用:使用不同的子网域提供与主来源网站目的截然不同的体验。例如,在新闻网站中,可以有意从
https://crosswords.example.com
提供填字游戏 Web 应用,并将其作为独立的 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
服务工件脚本网址的来源必须与调用 register() 的网页的来源相同。例如,这意味着位于 https://www.example.com
的网页无法使用位于 https://section.example.com
的服务工件网址调用 register()
。
另一个注意事项是,Service Worker 只能控制其所属来源和路径下托管的网页。这意味着,如果 Service Worker 托管在 https://www.example.com
上,则只能控制来自该来源的网址(根据范围参数中定义的路径),但不会控制其他子网中的任何网页,例如 https://section.example.com
中的网页。
在这种情况下,唯一的解决方法是使用多个服务工件(每个源站一个)。
缓存
Cache 对象、IndexedDB 和 localStorage 也只能用于单个源。这意味着,无法从 https://www.section.example.com
等位置访问属于 https://www.example.com
的缓存。
在这种情况下,您可以采取以下措施来妥善管理缓存:
利用浏览器缓存:始终建议使用传统的浏览器缓存最佳实践。这种方法还有一个额外的好处,即可以在多个源中重复使用缓存的资源,而服务工件的缓存无法做到这一点。如需了解如何将 HTTP 缓存与服务工件搭配使用,请参阅这篇文章。
让服务工件安装轻量化:如果您要维护多个服务工件,请避免让用户每次导航到新源时都付出巨大的安装费用。换句话说:仅预缓存绝对必要的资源。
权限
权限也受来源限制。这意味着,如果用户向来源 https://section.example.com
授予了给定权限,该权限不会延续到其他来源(例如 https://www.example.com
)。
由于无法跨源共享权限,因此唯一的解决方案是在需要使用给定功能(例如位置信息)的每个子网域上请求权限。对于 Web Push 等功能,您可以维护一个 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 中的任何结果信息传回父网页。
- 最后一步是,主页面收到消息后,可以取消注册监听器,并最终将 iframe 从 DOM 中移除。
总结
同源政策会对希望实现一致 PWA 体验的基于多个源构建的网站施加许多限制。因此,为了向用户提供最佳体验,我们强烈建议您不要将网站划分为不同的来源。
对于已按此方式构建的现有网站,要想让多源 PWA 正常运行可能很难,但我们已经探索出一些潜在的权宜解决方法。每种方法都有利弊,因此请根据自己的判断决定在网站上采用哪种方法。
评估长期策略或网站重新设计时,请考虑迁移到单源,除非有重要原因需要保留多源架构。
非常感谢以下人员提供技术审核和建议:Penny Mclachlan、Paul Covell、Dominick Ng、Alberto Medina、Pete LePage、Joe Medley、Cheney Tsai、Martin Schierle 和 Andre Bandarra。