如何构建多个 PWA,利用同一域名,让用户知道它们属于同一组织或服务。
在多源网站中的渐进式 Web 应用博文中,Demian 讨论了基于多个源构建的网站在尝试构建包含所有这些源的单个渐进式 Web 应用时所面临的挑战。
此类网站架构的一个示例是电子商务网站,其中:
- 首页位于
https://www.example.com
。 - 类别页面托管在
https://category.example.com
上。 https://product.example.com
中的商品详情页面。
正如本文所述,同源政策会施加多项限制,以防止跨源共享服务工件、缓存和权限。因此,我们强烈建议您避免使用此类配置;对于已采用此类配置构建网站的用户,请尽可能考虑迁移到单源网站架构。
在本博文中,我们将介绍相反的情况:我们将分析希望利用相同网域名提供多个 PWA 并让用户知道这些 PWA 属于同一组织或服务的公司的情况,而不是介绍在不同来源中提供单个 PWA 的情况。
您可能已经注意到,我们使用了不同的但相互关联的术语,例如网域和来源。在继续之前,我们先回顾一下这些概念。
技术术语
- 网域:域名系统 (DNS) 中定义的任何标签序列。例如:
com
和example.com
是网域。 - 主机名:解析为至少一个 IP 地址的 DNS 条目。例如:
www.example.com
是主机名,example.com
可以是主机名(如果它具有 IP 地址),而com
永远不会解析为 IP 地址,因此永远不可能是主机名。 - 来源:架构、主机名和(可选)端口的组合。例如,
https://www.example.com:443
是起源。
顾名思义,同源政策对源站进行了限制,因此我们在整篇文章中主要会提到这个术语。不过,我们会不时使用“网域”或“子网域”来描述所使用的技术,以便创建不同的“来源”。
多个相关 PWA 的情况
在某些情况下,您可能希望构建独立应用,但仍将其标识为属于同一组织或“品牌”。重复使用相同的域名是建立这种关系的好方法。例如:
- 某个电子商务网站希望打造独立的体验,让卖家管理其商品目录,同时确保卖家了解该目录属于用户购买商品的主要网站。
- 某体育新闻网站希望为重大体育赛事构建一款特定应用,让用户可以通过通知接收自己喜爱的比赛的统计信息,并将其作为渐进式 Web 应用进行安装,同时确保用户能够将其识别为新闻公司开发的应用。
- 某公司想要构建单独的聊天、邮件和日历应用,并希望这些应用作为单独的应用运行,并与公司名称相关联。
使用单独的来源
在这种情况下,建议的方法是让每个在概念上不同的应用都位于自己的来源。
如果您想在所有这些子网中使用同一域名,可以使用子网域来实现此目的。例如,提供多个互联网应用或服务的公司可以在 https://mail.example.com
上托管邮件应用或在 https://calendar.example.com
上托管日历应用,同时在 https://www.example.com
上提供其业务的主要服务。再举一个例子,某个体育网站想要创建一个完全专用于重要体育赛事(例如 https://footballcup.example.com
举办的足球锦标赛)的独立应用,让用户可以独立于托管在 https://www.example.com
的主体育网站之外安装和使用该应用。对于那些让客户以公司品牌的名义自行创建独立应用的平台,此方法可能也很有用。例如,允许商家在 https://merchant1.example.com
、https://merchant2.example.com
等位置创建自己的 PWA 的应用。
使用不同的来源可确保应用之间隔离,这意味着每个应用都可以独立管理不同的浏览器功能,包括:
- 可安装性:每个应用都有自己的清单,并提供自己的可安装体验。
- 存储空间:每个应用都有自己的缓存、本地存储空间,以及基本上所有形式的设备本地存储空间,而不会与其他应用共享这些存储空间。
- Service Worker:对于已注册的范围,每个应用都有自己的 Service Worker。
- 权限:权限也按来源进行限定。这样一来,用户将确切知道自己向哪项服务授予了权限,并且通知等功能将正确归因于各个应用。
对于多个独立 PWA 的用例,创建这种程度的隔离是最可取的做法,因此我们强烈建议您使用此方法。
如果子网域上的应用想要彼此共享本地数据,仍然可以通过 Cookie 来实现;对于更高级的场景,它们可以考虑通过服务器同步存储空间。
使用相同的来源
第二种方法是在同一源上构建不同的 PWA。这包括以下场景:
不重叠的路径
在同一源上托管的多个 PWA 或概念性“Web 应用”,路径不重叠。例如:
https://example.com/app1/
https://example.com/app2/
重叠/嵌套路径
同一源上的多个 PWA,其中一个作用域嵌套在另一个作用域中:
https://example.com/
(“外部应用”)https://example.com/app/
(“内部应用”)
借助服务工件 API 和清单格式,您可以使用路径级范围来执行上述任一操作。不过,在这两种情况下,使用同一来源会带来许多问题和限制,导致浏览器无法完全将其视为不同的“应用”的根本原因在于,不建议采用此方法。
在下一部分中,我们将更详细地分析这些挑战,以及在无法使用单独的来源时可以采取哪些措施。
多个同源 PWA 面临的挑战
以下是这两种同源方法经常遇到的一些实际问题:
- 存储空间:Cookie、本地存储空间以及所有形式的设备本地存储空间在应用之间共享。因此,如果用户决定擦除某个应用的本地数据,系统会擦除来源中的所有数据;无法仅针对单个应用执行此操作。请注意,Chrome 和某些其他浏览器会在卸载某个应用时主动提示用户擦除本地数据,这也会影响来源中其他应用的数据。另一个问题是,应用还必须共享其存储空间配额,这意味着,如果其中一个应用占用过多空间,另一个应用将受到负面影响。
- 权限:浏览器权限与来源相关联。也就是说,如果用户向一款应用授予权限,该权限将同时应用于该来源中的所有应用。这可能听起来不错(无需多次请求权限),但请注意:如果用户阻止授予某个应用权限,则会阻止其他应用请求该权限或使用该功能。请注意,即使每个来源只需授予一次浏览器权限,但另一方面,系统级权限必须为每个应用授予一次,无论多个应用是否指向同一来源。
- 用户设置:您还可以按来源设置。例如,如果两个应用的字体大小不同,而用户只想调整其中一个应用的缩放比例来进行补偿,则必须将该设置应用于其他应用,否则无法实现。
这些挑战使得我们很难鼓励采用这种方法。不过,如果您无法使用单独的来源(例如子网域),如使用单独的来源部分所述,在我们提供的两个同源选项中,我们强烈建议您使用非重叠路径,而不是重叠/嵌套路径。
如前所述,本部分讨论的挑战对这两种同源方法来说都很常见。在下一部分中,我们将详细介绍为何最不建议使用重叠/嵌套路径。
重叠/嵌套路径的其他挑战
重叠/嵌套路径方法(其中 https://example.com/
是外部应用,https://example.com/app/
是内部应用)的另一个问题是,内部应用中的所有网址实际上将被视为外部应用和内部应用的一部分。
在实践中,这会带来以下问题:
- 安装促销:如果用户访问内部应用(例如在网络浏览器中),当外部应用已安装在用户设备上时,浏览器不会显示安装促销横幅,并且不会触发 BeforeInstallPrompt 事件。原因在于,浏览器会检查当前网页是否属于已安装的应用,并会得出该网页属于已安装应用的结论。解决方法是手动安装内部应用(通过“创建快捷方式”浏览器菜单选项),或先安装内部应用,然后再安装外部应用。
- 通知和 Badging API:如果外部应用已安装,但内部应用未安装,则来自内部应用的通知和标记将错误地归因于外部应用(即已安装应用的最近封闭作用域)。如果这两个应用都安装在用户的设备上,此功能会正常运行。
- 链接捕获:外部应用可能会捕获属于内部应用的网址。如果外部应用已安装,但内部应用未安装,这种情况尤其可能发生。同样,外部应用中指向内部应用的链接也不会将链接捕获到内部应用,因为它们被视为位于外部应用的范围内。此外,在 ChromeOS 和 Android 上,如果这些应用添加到 Play 商店(作为受信任的 Web 活动),外部应用将捕获所有链接。即使安装了内部应用,操作系统仍会为用户提供在外部应用中打开它们的选项。
总结
在本文中,我们介绍了开发者可以在同一网域中构建多个彼此相关的渐进式 Web 应用的不同方式。
总而言之,我们强烈建议您使用其他来源(例如,使用子网域)来托管独立的 PWA。在同一源中托管它们会带来诸多挑战,这主要是因为浏览器不会完全将它们视为不同的应用。
- 使用单独的来源:推荐
- 同源、不重叠的路径:不推荐
- 同源、路径重叠/嵌套:强烈建议不要
如果无法使用不同的来源,强烈建议使用不重叠的路径(例如 https://example.com/app1/
和 https://example.com/app2/
),而不是使用重叠或嵌套的路径,例如 https://example.com/
(外部应用)和 https://example.com/app/
(内部应用)。
其他资源
Joe Medley、Dominick Ng、Alan Cutter、Daniel Murphy、Penny McLachlan、Thomas Steiner 和 Darwin Huang 感谢他们提供技术审核和建议
照片由 Tim Mossholder 拍摄,选自 Unsplash