共享存储 API
概念和用法
网络上隐私和安全问题的一个主要来源是,在网站中嵌入的第三方内容(例如通过 <iframe>
元素)上设置的 Cookie。这些 Cookie 可用于跟踪和分析用户,并在不同网站之间共享信息。
为了防止跨站点跟踪,浏览器正在努力对所有存储类型进行分区,包括 Cookie、网页存储、IndexedDB 和 缓存 API。然而,实现这一目标的一个主要障碍是,需要满足几个依赖于跨站点信息共享的合法用例。此类用例的示例包括广告商希望跨网站衡量广告的覆盖范围并生成报告,以及网站所有者希望根据用户的所属群体或之前的网站互动情况定制用户体验。
共享存储 API 为此类用例提供了一种灵活的解决方案。它旨在提供所需的数据存储、处理和共享功能,而无需跟踪和分析用户。
与其他存储 API 一样,您可以在任何时候写入共享存储。但是,您只能从 worklet 内部读取共享存储数据。Worklet 提供了一个安全的环境,您可以在其中处理共享存储数据并返回有用的结果,但您不能直接将数据与关联的浏览上下文共享。
要从共享存储 worklet 中提取有用的结果,您需要使用一个 **输出门**。这些门用于特定目的,例如根据共享存储数据从提供的列表中选择一个 URL 显示给用户。旨在用于用户的結果会安全地显示在一个 围栏框架 中,在那里他们无法从嵌入页面访问。
输出门
当前可用的共享存储 API 输出门在以下部分中讨论。在每个部分中,我们列出了每个门的典型用例,并提供了包含更多信息和代码示例的指南的链接。
注意: 未来可能会添加更多输出门来支持其他用例。
URL 选择
URL 选择 输出门,通过 selectURL()
方法访问,用于根据共享存储数据从提供的列表中选择一个 URL 显示给用户。此门可以用于以下目的:
运行
了解共享存储的工作原理
写入共享存储
将数据写入共享存储很简单——您使用在 SharedStorage
接口中定义的方法来 设置、追加 或 删除/清除 数据。
此功能在两种不同的上下文中可用:
- 在主浏览上下文(您的网站或应用程序运行的地方)上,在
WindowSharedStorage
上。这可以通过window.sharedStorage
访问。 - 在您的共享存储 worklet 的上下文中,在
WorkletSharedStorage
上。这可以通过this.sharedStorage
访问。
在我们的 A/B 测试示例中,我们在应用程序上下文中定义了一个函数,该函数生成一个随机数(0 或 1)来表示一个实验组。然后我们运行 window.sharedStorage.set()
函数来将用户分配到一个组并将结果保存到共享存储中。
// 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。
要使用输出门,您需要:
- 在 worklet 模块脚本中定义一个操作来处理 URL 选择,并将其注册。
- 将模块添加到您的共享存储 worklet。
- 使用 worklet 操作选择 URL 并将其加载到围栏框架中。
下面我们将逐一查看这些步骤。
在 worklet 模块中定义一个操作
URL 选择基于存储在共享存储中的实验组。要检索此值并根据其选择一个 URL,我们需要在 SharedStorageWorklet
上下文中定义一个操作。这确保了原始数据对其他上下文隐藏,从而保护隐私。
URL 选择操作是一个 JavaScript 类,必须遵循以下规则(这些规则因每个输出门的预期用例而异):
- 实际功能必须包含在一个异步
run()
方法中,该方法将包含 URL 的对象数组作为其第一个参数,并将数据对象作为其第二个参数(调用时,数据参数是可选的)。 run()
方法必须返回一个数字,该数字将等于所选 URL 的编号。
注意:每个输出门都有一个相应的接口,它定义了其类和 run()
方法所需的结构。对于 URL 选择,请参阅 SharedStorageSelectURLOperation
。
定义操作后,需要使用 SharedStorageWorkletGlobalScope.register()
来注册它。
// 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。在我们的主应用程序上下文中,这在我们设置实验组值之前完成,以便在需要时可以使用它。
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。
// 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>
元素中
document.getElementById("content-slot").config = fencedFrameConfig;
完整的应用程序脚本如下所示
// 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 存储之间的另一个重要区别是,从共享存储读取是受保护的(写入存储的行为类似)。使用 localStorage
和 sessionStorage
,您可以自由读取。使用共享存储,读取只能在共享存储工作集中进行,并且在工作集中用于读取的来源与创建它的浏览上下文相同。
此外,您无法在共享存储工作集之外提取共享存储数据,作为跟踪保护。您必须使用其中一个输出网关来处理共享存储中的数据。
最后,localStorage
中的数据会一直持续存在,直到手动清除。sessionStorage
在浏览会话结束时清除,而共享存储数据在最后一次写入调用后 30 天清除。
接口
-
表示特定来源的共享存储。它定义了将数据写入共享存储的方法。
-
表示特定来源的共享存储,如标准浏览上下文所示。除其他事项外,它定义了使用可用输出网关的方法,这些网关充当工作集中定义的操作的代理。
-
表示工作集上下文内特定来源的共享存储。除其他事项外,它定义了读取共享存储数据的方法。
-
表示当前来源的共享存储工作集。它包含用于添加模块的
addModule()
方法。与常规Worklet
不同,SharedStorageWorklet
只能添加一个模块,出于隐私原因。 -
表示
SharedStorageWorklet
模块的全局范围。它包含 注册 定义的操作和 访问共享存储 的功能。
输出网关操作签名定义
-
表示所有不同输出网关操作类型的基类。
-
表示运行输出网关操作。
-
表示 URL 选择输出网关操作。
对其他接口的扩展
-
返回当前来源的
WindowSharedStorage
对象。
注册和本地测试
要在您的网站中使用共享存储 API,您必须在 隐私沙箱注册流程 中指定它。如果您没有这样做,共享存储 API 方法将无法成功运行。
您可以在没有注册的情况下在本地测试您的共享存储 API 代码。要允许本地测试,请启用以下 Chrome 开发者标志
chrome://flags/#privacy-sandbox-enrollment-overrides
示例
有关扩展演示,请参阅 共享存储 API 演示网站,其中还包括一些私有聚合 API 示例。
规范
规范 |
---|
共享存储 API # sharedstorage |
浏览器兼容性
BCD 表格仅在启用 JavaScript 的浏览器中加载。