如何构建多个 PWA 并利用同一域名,让用户知道它们属于同一组织或服务。
在“多源网站中的渐进式 Web 应用”这篇博文中,Demian 讨论了基于多个源构建的网站在尝试构建涵盖所有这些源的单个渐进式 Web 应用时面临的挑战。
例如,电子商务网站就属于此类网站架构:
- 首页位于
https://www.example.com
。 - 类别网页托管在
https://category.example.com
上。 - 位于
https://product.example.com
的商品详情页面。
如本文中所述,同源政策施加了一些限制,防止在源之间共享 Service Worker、缓存和权限。因此,我们强烈建议您避免使用此类配置;对于那些已经以这种方式构建的网站的用户,我们强烈建议您尽可能迁移到单个源网站架构。
![示意图:某个网站分为多个源,同时指出在构建 PWA 时不建议采用该方法。](https://web.developers.google.cn/static/articles/building-multiple-pwas-on-the-same-domain/image/diagram-showing-site-div-64e98fc6031ee.png?authuser=9&hl=hu)
在这篇博文中,我们了解了相反的情况:我们将分析公司希望提供多个 PWA,利用同一域名,并让用户知道这些 PWA 属于同一组织或服务的情况,而不是跨不同来源的单个 PWA。
您可能已经注意到,我们使用了各种不同但相互关联的术语,例如“网域”和“来源”。在继续操作之前,我们先回顾一下这些概念。
技术术语
- 网域:域名系统 (DNS) 中定义的任何标签序列。
例如:
com
和example.com
就是网域。 - 主机名:解析为至少一个 IP 地址的 DNS 条目。例如:
www.example.com
是主机名,example.com
可以是主机名(如果它具有 IP 地址),而com
永远不会解析为 IP 地址,因此它也一定不能是主机名。 - 来源:协议、主机名和(可选)端口的组合。例如,
https://www.example.com:443
是一个源站。
顾名思义,同源政策对源站施加了限制,因此我们在整篇文章中主要引用该术语。不过,我们会不时使用“网域”或“子网域”来描述所使用的技术,以便创建不同的“来源”。
多个相关的 PWA 的情况
在某些情况下,您可能希望构建独立的应用,但仍要将这些应用标识为属于同一组织或“品牌”。重复使用同一域名是建立这种关系的好方法。例如:
- 某个电子商务网站希望打造一种独立的体验,使卖家能够管理自己的商品目录,同时确保他们了解该平台属于用户购买商品的主网站。
- 某体育新闻网站想要为重大体育赛事构建特定应用,让用户通过通知接收他们喜爱的比赛的统计数据,并将其作为渐进式 Web 应用进行安装,同时确保用户能够将其识别为新闻公司开发的应用。
- 一家公司想要构建单独的聊天、邮件和日历应用,并希望它们作为单独的应用运行,与公司的名称相关联。
![在尝试构建统一的 Progresive Web 应用时,请避免为同一网站的网站版块使用不同的来源。](https://web.developers.google.cn/static/articles/building-multiple-pwas-on-the-same-domain/image/avoid-using-different-ori-d78df43acb88b.png?authuser=9&hl=hu)
使用单独的源站
在此类情况下,建议的方法是为每个在概念上不同的应用在其源站上运行。
如果要在所有网域内使用相同的域名,您可以使用子网域。例如,一家提供多个互联网应用或服务的公司可以在 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 实现共享,对于更高级的场景,他们可以考虑通过服务器同步存储空间。
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/building-multiple-pwas-on-the-same-domain/image/alttexthere-699ea17734325.png?authuser=9&hl=hu)
使用同一来源
第二种方法是在同一源上构建不同的 PWA。这包括以下场景:
不重叠的路径
在同一来源上托管的多个 PWA 或概念性“Web 应用”,且路径不重叠。例如:
https://example.com/app1/
https://example.com/app2/
重叠/嵌套路径
同一源上的多个 PWA,其中一个作用域嵌套在另一个 PWA 内:
https://example.com/
(“外部应用”)https://example.com/app/
(“内部应用”)
借助 Service Worker API 和清单格式,您可以使用路径级范围限定执行上述任一操作。不过,在这两种情况下,使用同一来源会带来许多问题和限制,造成此问题和限制的根本原因在于浏览器不会将这些“应用”完全视为不同的“应用”,因此不建议采用这种方法。
![ALT_TEXT_HERE](https://web.developers.google.cn/static/articles/building-multiple-pwas-on-the-same-domain/image/alttexthere-67b559ff24375.png?authuser=9&hl=hu)
在下一部分中,我们将更详细地分析这些挑战,以及在无法使用不同源站的情况下可以采取的措施。
多个同源 PWA 的挑战
以下是这两种同源方法常见的一些实际问题:
- 存储:Cookie、本地存储空间以及各种形式的设备本地存储空间在应用之间共享。因此,如果用户决定擦除一个应用的本地数据,它将从源站擦除所有数据;无法针对单个应用执行此操作。请注意,卸载其中一个应用时,Chrome 和其他一些浏览器会主动提示用户擦除本地数据,这也会影响源站上其他应用的数据。另一个问题是,应用还必须共享其存储空间配额,这意味着如果其中一个应用占用过多空间,另一个将受到负面影响。
- 权限:权限与源网域相关联。这意味着,如果用户向某个应用授予某项权限,该权限将同时应用到该来源上的所有应用。这可能听起来不错(不必多次请求权限),但请注意:如果用户阻止对某个应用的权限,则会阻止其他应用请求该权限或使用此功能。
- 用户设置:也是按源站进行设置。例如,如果两个应用的字体大小不同,而用户只想调整其中一个应用的缩放比例来抵消字体大小,则只有在将该设置也应用于其他应用的情况下,他们才能执行此操作。
这些挑战使我们难以鼓励采用这种方法。不过,如果您无法使用我们介绍的两个同源选项中的单独来源(例如子网域)(如使用单独的源站部分中所述),强烈建议针对重叠/嵌套路径使用不重叠的路径。
如上所述,本部分介绍的挑战对于这两种同源方法都是常见的。在下一部分中,我们将更详细地介绍为什么最不推荐使用重叠/嵌套路径。
针对重叠/嵌套路径的其他挑战
重叠/嵌套路径方法(其中 https://example.com/
是外部应用,https://example.com/app/
是内部应用)的另一个问题是,内部应用中的所有网址实际上都被视为外部应用和内部应用的一部分。
实际上,这会带来以下问题:
- 安装宣传:如果用户访问内部应用(例如,在网络浏览器中),那么当用户的设备上已安装该外部应用时,浏览器不会显示安装宣传横幅,并且不会触发 BeforeInstallPrompt 事件。其原因在于,浏览器将检查并查看当前页面是否属于已安装的应用,从而得出结论。解决方法是手动安装内部应用(通过“创建快捷方式”浏览器菜单选项),或者先安装内部应用,然后再安装外部应用。
- 通知和 Badging API:如果已安装外部应用,但未安装内部应用,则来自内部应用的通知和标记将被错误地归因于外部应用(即已安装应用最近的封装范围)。如果用户设备上同时安装了这两款应用,此功能可正常运行。
- 链接捕获:外部应用可能会捕获属于内部应用的网址。如果已安装外部应用,但未安装内部应用,则尤为可能发生此类情况。同样,外部应用中链接到内部应用的链接也不会将捕获链接到内部应用,因为它们被视为位于外部应用的范围内。此外,在 ChromeOS 和 Android 上,如果这些应用被添加到 Play 商店(作为 Trusted Web Activity),则外部应用会捕获所有链接。即使安装了内部应用,操作系统仍会为用户提供在外部应用中打开它们的选项。
总结
在本文中,我们介绍了开发者可在同一网域内构建多个彼此相关的渐进式 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 用户)