共享存储 API

实验性: 这是一个 实验性技术
在生产环境中使用之前,请仔细查看 浏览器兼容性表

共享存储 API 是一种客户端存储机制,它允许无分区、跨站点数据访问,同时保护隐私(即不依赖于跟踪 Cookie)。

概念和用法

网络上隐私和安全问题的一个主要来源是,在网站中嵌入的第三方内容(例如通过 <iframe> 元素)上设置的 Cookie。这些 Cookie 可用于跟踪和分析用户,并在不同网站之间共享信息。

为了防止跨站点跟踪,浏览器正在努力对所有存储类型进行分区,包括 Cookie网页存储IndexedDB缓存 API。然而,实现这一目标的一个主要障碍是,需要满足几个依赖于跨站点信息共享的合法用例。此类用例的示例包括广告商希望跨网站衡量广告的覆盖范围并生成报告,以及网站所有者希望根据用户的所属群体或之前的网站互动情况定制用户体验。

共享存储 API 为此类用例提供了一种灵活的解决方案。它旨在提供所需的数据存储、处理和共享功能,而无需跟踪和分析用户。

与其他存储 API 一样,您可以在任何时候写入共享存储。但是,您只能从 worklet 内部读取共享存储数据。Worklet 提供了一个安全的环境,您可以在其中处理共享存储数据并返回有用的结果,但您不能直接将数据与关联的浏览上下文共享。

要从共享存储 worklet 中提取有用的结果,您需要使用一个 **输出门**。这些门用于特定目的,例如根据共享存储数据从提供的列表中选择一个 URL 显示给用户。旨在用于用户的結果会安全地显示在一个 围栏框架 中,在那里他们无法从嵌入页面访问。

输出门

当前可用的共享存储 API 输出门在以下部分中讨论。在每个部分中,我们列出了每个门的典型用例,并提供了包含更多信息和代码示例的指南的链接。

注意: 未来可能会添加更多输出门来支持其他用例。

URL 选择

URL 选择 输出门,通过 selectURL() 方法访问,用于根据共享存储数据从提供的列表中选择一个 URL 显示给用户。此门可以用于以下目的:

  • 创意轮播:使用存储的数据(例如创意 ID、查看次数和用户互动)确定用户在不同网站上看到的创意内容。这种方法有助于平衡浏览次数并防止某些内容过度曝光,进而可以帮助避免负面的用户体验。
  • A/B 测试:将用户分配到一个实验组,然后将组详细信息存储在共享存储中以便跨站点访问。
  • 自定义用户体验:根据用户的注册状态或其他用户状态共享自定义内容和号召性用语。

运行

运行 输出门,通过 run() 方法访问,旨在以通用方式使用,以处理一些共享存储数据。

私有聚合 API 可以使用运行输出门来处理共享存储数据并生成聚合报告。这些报告可以在以下用例中使用:

  • 唯一覆盖范围报告:内容制作人和广告商通常想知道其内容的唯一观看者数量。您可以使用共享存储来报告用户首次看到您的广告或嵌入式出版物的时间,并防止在不同网站上对同一用户进行重复计数,从而为您提供一个近似唯一覆盖范围的聚合噪声报告。
  • 用户人口统计报告:内容制作人通常希望了解其受众的人口统计数据。您可以使用共享存储来记录您主网站上的用户人口统计数据,并使用聚合报告在其他嵌入式上下文中的网站上报告该数据。
  • K+ 频率测量:有时被称为“有效频率”,K+ 频率是指用户在识别或回忆特定内容之前所需的最低观看次数(通常在广告观看次数的背景下使用)。您可以使用共享存储来构建至少看过内容 K 次的唯一用户的报告。

了解共享存储的工作原理

使用共享存储 API 包含两个部分——将数据写入存储和读取/处理数据。为了让您了解这些部分是如何处理的,我们将引导您完成 developer.chrome.com 中的基本 A/B 测试 示例。在此示例中,用户被分配到一个实验组,组详细信息存储在共享存储中。其他网站可以在选择在 围栏框架 中显示的 URL 时使用此数据。

写入共享存储

将数据写入共享存储很简单——您使用在 SharedStorage 接口中定义的方法来 设置追加删除/清除 数据。

此功能在两种不同的上下文中可用:

  • 在主浏览上下文(您的网站或应用程序运行的地方)上,在 WindowSharedStorage 上。这可以通过 window.sharedStorage 访问。
  • 在您的共享存储 worklet 的上下文中,在 WorkletSharedStorage 上。这可以通过 this.sharedStorage 访问。

在我们的 A/B 测试示例中,我们在应用程序上下文中定义了一个函数,该函数生成一个随机数(0 或 1)来表示一个实验组。然后我们运行 window.sharedStorage.set() 函数来将用户分配到一个组并将结果保存到共享存储中。

js
// Randomly assigns a user to a group 0 or 1
function getExperimentGroup() {
  return Math.round(Math.random());
}

async function injectContent() {
  // Assign user to a random group (0 or 1) and store it in shared storage
  window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
    ignoreIfPresent: true,
  });
}

注意:ignoreIfPresent: true 选项会导致 set() 函数在共享存储中已经包含具有指定键的数据项时中止。

从共享存储中读取和处理数据

如上所述,要从共享存储 worklet 中提取有用的结果,您需要使用一个 **输出门**。在此示例中,我们将使用 URL 选择输出门 来读取用户的实验组,然后根据其组在围栏框架中显示一个 URL。

要使用输出门,您需要:

  1. 在 worklet 模块脚本中定义一个操作来处理 URL 选择,并将其注册。
  2. 将模块添加到您的共享存储 worklet。
  3. 使用 worklet 操作选择 URL 并将其加载到围栏框架中。

下面我们将逐一查看这些步骤。

在 worklet 模块中定义一个操作

URL 选择基于存储在共享存储中的实验组。要检索此值并根据其选择一个 URL,我们需要在 SharedStorageWorklet 上下文中定义一个操作。这确保了原始数据对其他上下文隐藏,从而保护隐私。

URL 选择操作是一个 JavaScript 类,必须遵循以下规则(这些规则因每个输出门的预期用例而异):

  • 实际功能必须包含在一个异步 run() 方法中,该方法将包含 URL 的对象数组作为其第一个参数,并将数据对象作为其第二个参数(调用时,数据参数是可选的)。
  • run() 方法必须返回一个数字,该数字将等于所选 URL 的编号。

注意:每个输出门都有一个相应的接口,它定义了其类和 run() 方法所需的结构。对于 URL 选择,请参阅 SharedStorageSelectURLOperation

定义操作后,需要使用 SharedStorageWorkletGlobalScope.register() 来注册它。

js
// ab-testing-worklet.js
class SelectURLOperation {
  async run(urls, data) {
    // Read the user's experiment group from shared storage
    const experimentGroup = await this.sharedStorage.get("ab-testing-group");

    // Return the group number
    return experimentGroup;
  }
}

register("ab-testing", SelectURLOperation);

请注意,我们如何在主应用程序上下文中设置的值是使用 WorkletSharedStorage.get() 检索的。为了重申,为了保护隐私并减轻数据泄露,您只能在 worklet 中读取共享存储中的值。

注意:可以在同一个共享存储 worklet 模块脚本中使用不同的名称定义和注册多个操作;请参阅 SharedStorageOperation 以获取示例。

将模块添加到共享存储 worklet

要使用在 worklet 模块中定义的操作,需要使用 window.sharedStorage.worklet.addModule() 将其添加到共享存储 worklet。在我们的主应用程序上下文中,这在我们设置实验组值之前完成,以便在需要时可以使用它。

js
async function injectContent() {
  // Add the module to the shared storage worklet
  await window.sharedStorage.worklet.addModule("ab-testing-worklet.js");

  // Assign user to a random group (0 or 1) and store it in shared storage
  window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
    ignoreIfPresent: true,
  });
}

选择一个 URL 并将其加载到围栏框架中

为了执行工作集中定义的操作,我们调用 WindowSharedStorage.selectURL()。此方法充当我们工作集操作的代理,安全地访问它并返回结果,而不会泄露任何数据。selectURL() 是调用我们用户定义的工作集操作的正确方法,因为它使用上面讨论的适当类结构定义为 URL 选择操作。

selectURL() 期望一个包含要选择 URL 的对象的数组,一个可选的选项对象,以及底层操作返回一个整数,它可以使用该整数来选择 URL。

js
// Run the URL selection operation
const fencedFrameConfig = await window.sharedStorage.selectURL(
  "ab-testing",
  [
    { url: `https://your-server.example/content/default-content.html` },
    { url: `https://your-server.example/content/experiment-content-a.html` },
  ],
  {
    resolveToConfig: true,
  },
);

因为选项对象包含 resolveToConfig: true,所以返回的 Promise 将解析为一个 FencedFrameConfig 对象。此对象可以设置为 HTMLFencedFrameElement.config 属性的值,从而导致所选 URL 的内容显示在相应的 <fencedframe> 元素中

js
document.getElementById("content-slot").config = fencedFrameConfig;

完整的应用程序脚本如下所示

js
// Randomly assigns a user to a group 0 or 1
function getExperimentGroup() {
  return Math.round(Math.random());
}

async function injectContent() {
  // Add the module to the shared storage worklet
  await window.sharedStorage.worklet.addModule("ab-testing-worklet.js");

  // Assign user to a random group (0 or 1) and store it in shared storage
  window.sharedStorage.set("ab-testing-group", getExperimentGroup(), {
    ignoreIfPresent: true,
  });

  // Run the URL selection operation
  const fencedFrameConfig = await window.sharedStorage.selectURL(
    "ab-testing",
    [
      { url: `https://your-server.example/content/default-content.html` },
      { url: `https://your-server.example/content/experiment-content-a.html` },
    ],
    {
      resolveToConfig: true,
    },
  );

  // Render the chosen URL into a fenced frame
  document.getElementById("content-slot").config = fencedFrameConfig;
}

injectContent();

共享存储和网页存储之间的区别

关键区别在于共享存储旨在与存储分区后的跨域数据一起使用。

  • 如果您是发布者,并且想要存储仅您可访问的第一方数据,请使用 localStorage 版本的 web 存储
  • 如果您希望数据仅在浏览器会话期间持续存在,请使用 sessionStorage
  • 如果您在另一个网站上以第三方身份运行,并且想要记录来自该网站的数据以便稍后在另一个网站上访问,请使用共享存储。

共享存储和 web 存储之间的另一个重要区别是,从共享存储读取是受保护的(写入存储的行为类似)。使用 localStoragesessionStorage,您可以自由读取。使用共享存储,读取只能在共享存储工作集中进行,并且在工作集中用于读取的来源与创建它的浏览上下文相同。

此外,您无法在共享存储工作集之外提取共享存储数据,作为跟踪保护。您必须使用其中一个输出网关来处理共享存储中的数据。

最后,localStorage 中的数据会一直持续存在,直到手动清除。sessionStorage 在浏览会话结束时清除,而共享存储数据在最后一次写入调用后 30 天清除。

接口

SharedStorage

表示特定来源的共享存储。它定义了将数据写入共享存储的方法。

WindowSharedStorage

表示特定来源的共享存储,如标准浏览上下文所示。除其他事项外,它定义了使用可用输出网关的方法,这些网关充当工作集中定义的操作的代理。

WorkletSharedStorage

表示工作集上下文内特定来源的共享存储。除其他事项外,它定义了读取共享存储数据的方法。

SharedStorageWorklet

表示当前来源的共享存储工作集。它包含用于添加模块的 addModule() 方法。与常规 Worklet 不同,SharedStorageWorklet 只能添加一个模块,出于隐私原因。

SharedStorageWorkletGlobalScope

表示 SharedStorageWorklet 模块的全局范围。它包含 注册 定义的操作和 访问共享存储 的功能。

输出网关操作签名定义

SharedStorageOperation

表示所有不同输出网关操作类型的基类。

SharedStorageRunOperation

表示运行输出网关操作。

SharedStorageSelectURLOperation

表示 URL 选择输出网关操作。

对其他接口的扩展

Window.sharedStorage

返回当前来源的 WindowSharedStorage 对象。

注册和本地测试

要在您的网站中使用共享存储 API,您必须在 隐私沙箱注册流程 中指定它。如果您没有这样做,共享存储 API 方法将无法成功运行。

您可以在没有注册的情况下在本地测试您的共享存储 API 代码。要允许本地测试,请启用以下 Chrome 开发者标志

chrome://flags/#privacy-sandbox-enrollment-overrides

示例

有关扩展演示,请参阅 共享存储 API 演示网站,其中还包括一些私有聚合 API 示例。

规范

规范
共享存储 API
# sharedstorage

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参见