报告 API

W3C 工作草案,

关于本文件的更多信息
此版本:
https://www.w3.org/TR/2025/WD-reporting-1-20250611/
最新发布版本:
https://www.w3.org/TR/reporting-1/
编辑草案:
https://w3c.github.io/reporting/
历史版本:
历史记录:
https://www.w3.org/standards/history/reporting-1/
反馈:
GitHub
规范内反馈
编辑者:
(GitHub)
(Google Inc.)
(Google Inc.)
前任编辑者:
(Google Inc.)
(Google Inc.)

摘要

本文档定义了一个通用的报告框架,允许 Web 开发者为某个源(origin)关联一组具名的报告端点。各种平台特性可以使用这些端点,以一致的方式传递特定功能的报告。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 出版物列表及本技术报告的最新修订版可在 W3C 标准与草案索引 https://www.w3.org/TR/ 查询。

本文档由 Web 性能工作组 作为工作草案,并采用推荐标准流程发布。 作为工作草案发布,并不代表 W3C 及其成员的认可。

本文档为草案,可能随时被更新、替换或废弃。除非作为在研工作,否则不应引用本文件。

关于本规范的讨论,建议优先使用GitHub Issues。

本文件受 2023年11月3日 W3C 流程文档 管辖。

本文件由遵循 W3C 专利政策 的工作组制定。 W3C 维护了与本组交付物相关的专利披露公开列表; 该页面还包含专利披露说明。 任何知晓某项专利且认为其包含必要权利要求的个人,必须根据W3C 专利政策第6节披露相关信息。

1. 简介

本文档为通用报告提供了三项基础设施,可供其他规范使用或扩展:

  1. 用于定义报告类型和报告端点的通用框架,以及用于通过 HTTP 向端点发送报告的文档格式。

  2. 用于在文档或 worker 中配置报告端点的具体机制,并用于投递与该文档或 worker 生命周期绑定的报告。

  3. 用于观察文档或 worker 内生成报告的 JavaScript 接口。

其他规范可以扩展或利用这些基础设施,例如定义具体的报告类型,或为非文档类报告定义其他配置或投递机制。

1.1. 保证

本规范旨在提供一个尽力而为的报告投递系统,其执行与网站活动解耦。用户代理能够更好地优先处理和调度报告投递,因为它能全局了解跨源活动,而单个网站无法做到,并且可以根据阻止网站加载的错误条件来投递报告。

但报告的投递并无任何保证,报告机制也不应被用作可靠的通信通道。网络状况可能导致报告无法送达目的地,用户代理也可以因任何原因拒绝或不投递报告。

1.2. 示例

MegaCorp Inc. 希望收集内容安全策略(CSP)和密钥钉扎(HPKP)违规报告。它可以通过发送如下响应头来定义名为 "endpoint-1" 的报告端点:
Reporting-Endpoints: endpoint-1="https://example.com/reports"

以及如下响应头,将 CSP 和 HPKP 报告指向该端点:

Content-Security-Policy: ...; report-to endpoint-1
Public-Key-Pins: ...; report-to=endpoint-1
经过一段时间的报告处理后,MegaCorp Inc. 决定将这两类报告分开处理,以简化处理脚本。它可以通过如下响应头定义两个报告端点:
Reporting-Endpoints: csp-endpoint="https://example.com/csp-reports",
                        hpkp-endpoint="https://example.com/hpkp-reports"

以及如下响应头,将 CSP 和 HPKP 报告分别指向对应端点:

Content-Security-Policy: ...; report-to csp-endpoint
Public-Key-Pins: ...; report-to=hpkp-endpoint

2. 通用报告框架

本节定义了报告和端点的通用概念,以及如何将报告序列化为 application/reports+json 格式。

2.1. 概念

2.1.1. 端点

端点(endpoint)是指用于接收特定报告的地址,这些报告属于某个特定源(origin)。

每个端点都有一个name,为 ASCII 字符串。

每个端点都有一个url, 是一个URL。

每个端点都有一个failures,为非负整数,表示该端点连续未响应请求的次数。

2.1.2. 报告类型

报告类型(report type)是一个非空字符串,指定报告体中包含的数据集。

当定义一个报告类型(在本规范或其他规范中)时,可以指定其对 ReportingObserver 可见,即该类型的报告可被报告观察者观察。默认情况下,报告类型对报告观察者不可见。

2.1.3. 报告

报告(report)是一组任意数据,用户代理应将其投递到指定端点。

每个报告有一个body,为 null 或可序列化为JSON 文本的对象。报告体中的字段由报告的类型决定。

每个报告有一个url, 通常为生成报告的 Document 或 Worker 的地址。

注: 序列化 URL 时会去除用户名、密码和片段。参见 § 8.1 能力型 URL。

每个报告有一个user agent,即生成报告的请求的 User-Agent 头的值。

注: user agent 表示生成报告的页面的 User-Agent。这可能与上传报告到收集器时发送的 User-Agent 不同,例如浏览器选择使用“请求桌面站点”等非默认 UA 字符串时。

每个报告有一个destination,为字符串,表示报告将被发送到的端点的name。

每个报告有一个type,为报告类型。

每个报告有一个timestamp,记录报告生成的时间(自 unix 纪元以来的毫秒数)。

每个报告有一个attempts计数器,为非负整数,表示用户代理尝试投递该报告的次数。

2.2. 媒体类型

向指定端点 POST 报告时使用的媒体类型为 application/reports+json。

2.3. 将 data 作为 type 排队到 destination

要根据可序列化对象(data)、字符串(type)、另一个字符串(destination)、可选环境设置对象(settings)和可选URL(url)生成报告:

  1. 令 report 为一个新报告对象,其值初始化如下:

    body

    data

    user agent

    当前navigator.userAgent的值

    destination

    destination

    type

    type

    timestamp

    当前时间戳。

    attempts

    0

  2. 如果调用方未提供 url,则令 url 为 settings 的创建 URL。

  3. 将 url 的 username 设为空字符串,password 设为 null。

  4. 将 report 的 url 设为对 url 执行URL 序列化器(排除片段标志开启)的结果。

  5. 返回 report。

注: 报告观察者只能观察来自同一环境设置对象的报告。

注: 报告中的序列化 URL 会去除用户名、密码和片段。参见 § 8.1 能力型 URL。

注: 用户代理可因任何原因拒绝报告。例如,本 API 不保证可投递任意数量的数据。

注: 非用户代理客户端(无 JavaScript 引擎)不应与报告观察者交互,因此应在第6步直接返回。

2.4. 序列化报告

要将 reports 列表序列化为 JSON:

  1. 令 collection 为一个空列表。

  2. 对 reports 中的每个 report:

    1. 令 data 为包含以下键值对的映射:

      age

      report 的 timestamp 与当前时间的毫秒差值。

      type

      report 的 type

      url

      report 的 url

      user_agent

      report 的 user agent

      body

      report 的 body

      注: 客户端时钟不可靠且可能有偏差,因此我们传递 age 属性而非绝对时间戳。参见 § 9.2 时钟偏差

    2. 将 report 的 attempts 加一。

    3. 将 data 添加到 collection。

  3. 返回对 collection 执行字节序列化的结果,即将 Infra 值序列化为 JSON 字节。

3. 基于文档的报告

本节定义了为文档(或 worker 脚本)中产生的报告配置报告端点的机制。这类报告的生命周期与其生成的文档或 worker 绑定。

3.1. 文档配置

每个实现 WindowOrWorkerGlobalScope 的对象都有一个 endpoints 列表, 该列表是端点的集合,每个端点的 name 必须唯一。 (唯一性由 § 3.3 响应中处理报告端点中的算法保证。)

每个实现 WindowOrWorkerGlobalScope 的对象都有一个 reports 列表,为报告的集合。

要初始化全局对象的端点列表,给定 WindowOrWorkerGlobalScope (scope)和 response(response), 将 scope 的 endpoints 设为执行 § 3.3 响应中处理报告端点(传入 response)的结果。

服务器可以通过 Reporting-Endpoints HTTP 响应头字段,为其返回的文档或 worker 脚本资源定义一组报告端点。 该机制定义见 § 3.2,其处理见 § 3.3。

Reporting-Endpoints HTTP 响应头字段的值用于构建资源的报告配置。

Reporting-Endpoints 是一个字典结构字段(Dictionary Structured Field)[STRUCTURED-FIELDS]。字典中的每个条目定义了一个可投递报告的端点。条目值必须为字符串。

每个端点由字符串项定义,解释为 URI-reference。若其值不是有效的 URI-reference,则该端点成员必须被忽略。

此外,该成员值所代表的 URL 必须是潜在可信的[SECURE-CONTEXTS]。非安全端点将被忽略。

端点不定义任何参数,指定的参数将被静默忽略。

该头部的 ABNF 语法如下 [RFC5234]:

Reporting-Endpoints = sf-dictionary
        

3.3. 响应中处理报告端点

给定 response(response),该算法提取并返回端点列表。

  1. 如果 response 的 HTTPS 状态不是 "modern",且 response 的 origin 不是潜在可信,则终止这些步骤。

  2. 令 parsed header 为对 response 的 header list 执行 get a structured field value(参数为 "Reporting-Endpoints" 和 "dictionary")的结果。

  3. 如果 parsed header 为 null,则终止这些步骤。

  4. 令 endpoints 为一个空列表。

  5. 对 parsed header 的每个 name → value_and_parameters:

    1. 令 endpoint url string 为 value_and_parameters 元组的第一个元素。如果 endpoint url string 不是字符串,则继续。

    2. 令 endpoint url 为对 endpoint url string 执行 URL 解析器(基准 URL 为 response 的 url)。如果 endpoint url 失败,则继续。

    3. 如果 endpoint url 的 origin 不是潜在可信,则继续。

    4. 令 endpoint 为一个新端点,其属性如下:

      name

      name

      url

      endpoint url

      failures

      0

    5. 将 endpoint 添加到 endpoints。

  6. 返回 endpoints。

3.4. 报告生成

3.4.1. 生成 type 和 data 的报告

当用户代理要为 Document 或 WorkerGlobalScope 对象(context), 给定字符串(type)、字符串(destination)和可序列化对象(data)时,要生成并排队报告,应执行以下步骤:

  1. 令 settings 为 context 的 相关设置对象。

  2. 令 report 为运行 生成报告(参数为 data、type、destination 和 settings)的结果。

  3. 如果 settings 存在,则

    1. 令 scope 为 settings 的 全局对象。

    2. 如果 scope 是实现了 WindowOrWorkerGlobalScope 的对象, 则执行 § 4.2 用 report 通知报告观察者,参数为 scope 和 report。

  4. 将 report 添加到 context 的 reports 列表。

3.5. 报告投递

随着时间推移,各种特性会在文档和 worker 中排队一系列报告。用户代理会定期获取当前排队的报告列表,并将其投递到关联的端点。本文档不定义用户代理应遵循的调度计划,假定用户代理有足够的上下文信息以在不影响用户体验的前提下及时投递报告。

也就是说,用户代理应尽快在排队后投递报告,因为报告的数据在生成后不久更有价值。

3.5.1. 发送报告

用户代理为 WindowOrWorkerGlobalScope 对象(context)发送 报告列表(reports)时,执行以下步骤:

  1. 令 endpoint map 为 端点对象到报告对象列表的空映射。

  2. 对 reports 中的每个 report:

    1. 如果 context 的 endpoints 列表中存在 name 等于 report 的 destination 的端点(endpoint):

      1. 将 report 添加到 endpoint map 中 endpoint 的报告列表。

      2. 否则,从 reports 中移除 report。

  3. 对 endpoint map 中的每个 (endpoint, report list) 对:

    1. 令 origin map 为 origin 到报告对象列表的空映射。

    2. 对 report list 中的每个 report:

      1. 令 origin 为 report 的 url 的 origin。

      2. 将 report 添加到 origin map 中 origin 的报告列表。

    3. 对 origin map 中的每个 (origin, per-origin reports) 对,异步执行以下步骤:

      1. 令 result 为对 endpoint、origin 和 per-origin reports 执行 § 3.5.2 尝试将报告投递到端点 的结果。

      2. 如果 result 为 "Failure":

        1. 将 endpoint 的 failures 加一。

      3. 如果 result 为 "Remove Endpoint":

        1. 从 context 的 endpoints 列表中移除 endpoint。

      4. 从 reports 中移除每个report。

      这里未指定失败报告的重试机制。我们可能需要在此添加,或提供投递失败的指示。

注: 用户代理可以只尝试投递部分收集到的报告或端点(例如,一次性发送所有报告会消耗过多带宽等)。报告仅在尝试投递后才会从缓存中移除,跳过的报告会在之后被投递。

3.5.2. 尝试将 reports 投递到 endpoint

给定 端点 (endpoint)、origin (origin)和报告列表(reports),该算法会构造一个请求并尝试将其投递到 endpoint。若投递成功返回 "Success",若端点通过 410 响应明确移除自身则返回 "Remove Endpoint",否则返回 "Failure"。

  1. 令 body 为对 reports 执行 将报告列表序列化为 JSON 的结果。

  2. 令 request 为一个新请求,属性如下 [FETCH]:

    method

    "POST"

    url

    endpoint 的 url

    origin

    origin

    header list

    包含名为 Content-Type 且值为 application/reports+json 的header list

    client

    null

    window

    "no-window"

    service-workers mode

    "none"

    initiator

    ""

    destination

    "report"

    mode

    "cors"

    unsafe-request flag

    已设置

    credentials

    "same-origin"

    body

    其body的source为 body。

    注: 报告发送时 credentials 设为 same-origin。这允许与报告页面同源的端点获得更多上下文,例如了解某用户是否持续触发错误,或某些操作序列是否导致报告。这不会向端点泄露其本可通过其他方式获得的新信息。跨域端点不会获得凭据。

  3. 排队任务以fetch request。

  4. 等待响应(response)。

  5. 如果 response 的 status 是OK 状态 (200-299),返回 "Success"。

  6. 如果 response 的 status 为 410 Gone [RFC9110],返回 "Remove Endpoint"。

  7. 返回 "Failure"。

3.6. 报告中使用的 URL 处理

要报告中使用的 URL 处理,给定 URL url,执行以下步骤,返回报告中使用的 URL 字符串。
  1. 如果 url 的 scheme 不是HTTP(S) scheme, 则返回 url 的 scheme。

  2. 将 url 的 fragment 设为空字符串。

  3. 将 url 的 username 设为空字符串。

  4. 将 url 的 password 设为空字符串。

  5. 返回对 url 执行 URL 序列化器 的结果。

4. 报告观察者

报告观察者用于从 JavaScript 观察某些类型的报告,在 JavaScript 中由 ReportingObserver 对象表示。

每个实现 WindowOrWorkerGlobalScope 的对象都有一个 已注册报告观察者列表, 是有序集合,元素为报告观察者。

任何在已注册报告观察者列表中的报告观察者都被视为已注册。

每个实现 WindowOrWorkerGlobalScope 的对象都有一个 报告缓冲区,为在该 WindowOrWorkerGlobalScope 中生成的报告的列表。初始为空,报告按生成顺序存储。

注: 报告缓冲区的目的是允许报告观察者观察早于其创建时机生成的报告(通过 buffered 选项)。例如,某些报告可能在页面加载早期阶段生成,此时观察者尚未创建,或 JavaScript 库尚未加载。

注: 报告观察者仅适用于带有 JavaScript 引擎的用户代理。

4.1. 接口 ReportingObserver

dictionary ReportBody {
};

dictionary Report {
  DOMString type;
  DOMString url;
  ReportBody? body;
};

[Exposed=(Window,Worker)]
interface ReportingObserver {
  constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options = {});
  undefined observe();
  undefined disconnect();
  ReportList takeRecords();
};

callback ReportingObserverCallback = undefined (sequence<Report> reports, ReportingObserver observer);

dictionary ReportingObserverOptions {
  sequence<DOMString> types;
  boolean buffered = false;
};

typedef sequence<Report> ReportList;

Report 是面向应用暴露的报告表示。

ReportBody 是抽象字典类型,具体报告类型应继承自它。

每个 ReportingObserver 对象有如下关联概念:

ReportList 表示 Report 的序列,开发者可像操作 JavaScript 数组一样使用。

ReportingObserver(callback, options) 构造函数被调用时,执行以下步骤:

  1. 创建一个新的 ReportingObserver 对象 observer。

  2. 将 observer 的 回调设为 callback。

  3. 将 observer 的 options 设为 options。

  4. 返回 observer。

observe() 方法被调用时,执行以下步骤:

  1. 令 global 为 相关全局对象。

  2. 将 this 添加到 global 的 已注册报告观察者列表。

  3. 如果 this 的 buffered 选项为 false,则返回。

  4. 将 this 的 buffered 选项设为 false。

  5. 对 global 的 报告缓冲区中的每个 report,排队任务执行 § 4.3 将报告添加到观察者,参数为 report 和 this。

disconnect() 方法被调用时,执行以下步骤:

  1. 如果 this 未注册,则返回。

  2. 令 global 为 this 的相关全局对象。

  3. 从 global 的 已注册报告观察者列表中移除 this。

takeRecords() 方法被调用时,执行以下步骤:

  1. 令 reports 为 this 的 报告队列的副本。

  2. 清空 this 的 报告队列。

  3. 返回 reports。

4.2. 在 scope 上用 report 通知报告观察者

该算法使 report 的内容可被提供的 WindowOrWorkerGlobalScope 上所有已注册的报告观察者获取。

  1. 对 scope 上每个已注册的 ReportingObserver observer,执行 § 4.3 将报告添加到观察者,参数为 report 和 observer。

  2. 将 report 添加到 scope 的 报告缓冲区。

  3. 令 type 为 report 的 type。

  4. 如果 scope 的 报告缓冲区中 type 等于 type 的报告超过 100 个,则移除缓冲区中最早的同类型报告。

4.3. 将 report 添加到 observer

给定 报告 report 和 ReportingObserver observer,该算法会将 report 添加到 observer 的报告队列,前提是 report 的 type 可被 observer 观察。

  1. 如果 report 的 type 不对 ReportingObserver 可见,则返回。

  2. 如果 observer 的 options 的 types 非空且不包含 report 的 type,则返回。

  3. 创建一个新的 Report r,其 type 初始化为 report 的 type,url 初始化为 report 的 url,body 初始化为 report 的 body。

如何多态初始化 body?

  1. 将 r 添加到 observer 的 报告队列。

  2. 如果 observer 的 报告队列 长度为 1:

    1. 令 global 为 observer 的 相关全局对象。

    2. 排队任务,以 global 的 已注册报告观察者列表副本为参数,执行 § 4.4 用 notify list 调用报告观察者。

4.4. 用 notify list 调用报告观察者

该算法为先前观察到的报告调用观察者回调函数。

  1. 对 notify list 中每个 ReportingObserver observer:

    1. 如果 observer 的 报告队列为空,则继续。

    2. 令 reports 为 observer 的 报告队列的副本。

    3. 清空 observer 的 报告队列。

    4. 调用 observer 的 回调,参数为 « reports, observer » 和 "report",observer 作为 callback this value。

5. 实现注意事项

5.1. 投递

用户代理应尽快尝试投递报告,以便开发者能尽早获得反馈。但在用户体验和及时反馈之间权衡时,应优先考虑用户体验。因此,用户代理可以根据对用户活动和上下文的了解,延迟报告的投递。

例如,用户代理应将报告数据的传输优先级低于其他网络流量。用户在网站上的显式操作应优先于报告流量。

用户代理可以选择在用户处于快速、低价网络时才投递报告,以避免不必要的数据费用。

用户代理可以选择优先投递来自特定源(如用户经常访问的站点)的报告。

5.2. 垃圾回收

用户代理应定期遍历缓存的报告和端点,丢弃那些不再相关的内容,包括:

对于被丢弃的报告,也应从任何报告观察者的报告缓冲区中移除。

6. 报告示例

本节为非规范性内容。

本示例展示了用户代理向报告端点发送报告时的格式。示例提交包含三个报告,这些报告被打包在一个 HTTP 请求中发送。(报告类型和内容仅为示例,与实际功能无关,超出本规范范围。)

POST / HTTP/1.1
Host: example.com
...
Content-Type: application/reports+json

[{
    "type": "security-violation",
    "age": 10,
    "url": "https://example.com/vulnerable-page/",
    "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
    "body": {
    "blocked": "https://evil.com/evil.js",
    "policy": "bad-behavior 'none'",
    "status": 200,
    "referrer": "https://evil.com/"
    }
}, {
    "type": "certificate-issue",
    "age": 32,
    "url": "https://www.example.com/",
    "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
    "body": {
    "date-time": "2014-04-06T13:00:50Z",
    "hostname": "www.example.com",
    "port": 443,
    "effective-expiration-date": "2014-05-01T12:40:50Z",
    "served-certificate-chain": [
        "-----BEGIN CERTIFICATE-----\n
        MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n
        ...
        HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto\n
        WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6\n
        yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx\n
        -----END CERTIFICATE-----",
        ...
    ]
    }
}, {
    "type": "cpu-on-fire",
    "age": 29,
    "url": "https://example.com/thing.js",
    "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0",
    "body": {
    "temperature": 614.0
    }
}]

7. 自动化

为支持用户代理自动化和应用测试,本文档为 [WebDriver] 规范定义了一些 扩展命令。

7.1. 生成测试报告

生成测试报告 扩展命令用于测试目的,模拟生成一个报告。该报告会被所有已注册的报告观察者观察到。

该扩展命令定义如下:

dictionary GenerateTestReportParameters {
  required DOMString message;
  DOMString group = "default";
};
HTTP 方法 URI 模板
POST /session/{session id}/reporting/generate_test_report

其 远端步骤如下:

  1. 如果 parameters 不是 JSON 对象,返回 WebDriver 错误,错误码为 invalid argument。

  2. 令 message 为 尝试获取 parameters 的 message 属性的结果。

  3. 如果 message 不存在,返回 WebDriver 错误,错误码为 invalid argument。

  4. 如果当前浏览上下文已关闭,返回 WebDriver 错误,错误码为 no such window。

  5. 处理所有用户提示,如返回 WebDriver 错误则直接返回。

  6. 令 group 为 parameters 的 group 属性。

  7. 令 body 为一个可序列化为 JSON 文本的新对象,包含一个字符串字段 body_message。

  8. 将 body_message 设为 message。

  9. 令 settings 为 环境设置对象,对应当前浏览上下文的活动文档。

  10. 执行 生成并排队报告,参数为 body、"test"、group 和 settings。

  11. 返回 success,数据为 null。

8. 安全性注意事项

8.1. 能力型 URL

某些 URL 本身就具有价值。它们可能在用户名和密码部分包含显式凭据,或仅凭 URL 路径即可授予资源访问权限。此外,URL 的 fragment 可能包含本不应离开用户浏览器的信息。更多信息参见 [CAPABILITY-URLS]。

为降低此类 URL 通过报告机制泄露的风险,相关算法会在作为报告来源发送的 URL 中去除凭据和 fragment 信息。但 URL 路径中的敏感信息仍有可能被泄露。使用此类 URL 的站点可能需要自建报告端点。

此外,此类 URL 也可能出现在报告的body中。扩展本 API 并在报告body中包含 URL 的规范,应要求同样去除敏感信息。

9. 隐私注意事项

9.1. 网络泄露

由于页面加载与报告生成、发送之间存在延迟,完全可能出现用户在一个网络上生成报告、但在另一个网络上发送报告的情况。

不过,这种行为仅限于生成报告的文档生命周期内。即使文档关闭,也可能通过 navigator.sendBeacon 等机制在新网络上产生流量。

需考虑缓解措施。例如,网络切换时可丢弃报告。[WICG/background-sync Issue #107]

9.2. 时钟偏差指纹

每个报告随 age 属性一同投递,而不是生成时的时间戳。这样做是因为每个用户本地时钟与服务器时钟可能有任意偏差。报告生成与发送的时间差是稳定的,可以避免通过本 API 暴露时钟偏差带来的指纹风险。

9.3. 跨源关联

如果多个源都使用同一个报告端点,该端点可能获知某用户访问过哪些网站,因为它会收到带有源信息的报告。这种能力并不比当前合作源间可追踪的信息更强,也不会带来超出 <img> 等机制的新追踪能力。

9.4. 禁用报告

报告机制在整体上对所有人都有益处。开发者能及时修复 bug,用户也能间接受益。例如,内容安全策略(CSP)通过报告潜在漏洞,为跨站脚本攻击提供“群体免疫”。修复这些漏洞有利于所有用户,即使他们的用户代理不支持 CSP。

当然,具体价值取决于所传递数据的性质和报告端点的可信程度,但总体上这是有益的。

但这种整体利益不能凌驾于用户个体选择退出的权利之上。发送报告会消耗带宽,也可能泄露网站本身无法直接获得的少量额外信息(如 [NETWORK-ERROR-LOGGING])。用户代理必须允许用户以合理粒度禁用报告,以维护 [HTML-DESIGN-PRINCIPLES] 所倡导的优先级。

10. IANA 注意事项

10.1. Reporting-Endpoints 头部

应更新永久消息头字段注册表,内容如下:[RFC3864]

头字段名称

Reporting-Endpoints

适用协议

http

状态

standard

作者/变更控制者

W3C

规范文档

本规范(见 § 3.2 Reporting-Endpoints HTTP 响应头字段)

10.2. application/reports+json 媒体类型

类型名称

application

子类型名称

reports+json

必需参数

N/A

可选参数

N/A

编码注意事项

编码注意事项与 "application/json" 媒体类型一致。参见 [RFC8259]。

安全性注意事项

见 § 8 安全性注意事项。

互操作性注意事项

本文档规定了符合要求的消息格式及其解释。

已发布规范

§ 2.2 媒体类型

使用该媒体类型的应用
片段标识符注意事项
附加信息

N/A

联系人及邮箱

本文件编辑者。

预期用途

COMMON

使用限制

N/A

作者

本文件编辑者。

变更控制者

W3C

临时注册?

是

索引

本规范定义的术语

引用规范定义的术语

参考文献

规范性引用

[DOM]
Anne van Kesteren. DOM 标准. Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; 等. HTML 标准. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
[RDF12-CONCEPTS]
Olaf Hartig; 等. RDF 1.2 概念与抽象语法. 2025年6月6日. WD. URL: https://www.w3.org/TR/rdf12-concepts/
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. 消息头字段注册流程. 2004年9月. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc3864
[RFC5234]
D. Crocker, Ed.; P. Overell. ABNF 语法规范. 2008年1月. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc5234
[RFC8259]
T. Bray, Ed.. JavaScript 对象表示法 (JSON) 数据交换格式. 2017年12月. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8259
[RFC9110]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP 语义. 2022年6月. Internet Standard. URL: https://httpwg.org/specs/rfc9110.html
[SECURE-CONTEXTS]
Mike West; Yan Zhu. 安全上下文. URL: https://w3c.github.io/webappsec-secure-contexts/
[STRUCTURED-FIELDS]
Mark Nottingham; Poul-Henning Kamp. HTTP 结构化字段值. URL: https://www.rfc-editor.org/rfc/rfc8941.html
[URL]
Anne van Kesteren. URL 标准. Living Standard. URL: https://url.spec.whatwg.org/
[WebDriver]
Simon Stewart; David Burns. WebDriver. 2018年6月5日. REC. URL: https://www.w3.org/TR/webdriver1/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. Living Standard. URL: https://webidl.spec.whatwg.org/

参考性引用

[CAPABILITY-URLS]
Jeni Tennison. 能力型 URL 的最佳实践. 2014年2月18日. FPWD. URL: https://www.w3.org/TR/capability-urls/
[CSP3]
Mike West; Antonio Sartori. 内容安全策略第3级. 2025年6月6日. WD. URL: https://www.w3.org/TR/CSP3/
[HTML-DESIGN-PRINCIPLES]
Anne van Kesteren; Maciej Stachowiak. HTML 设计原则. 2007年11月26日. WD. URL: https://www.w3.org/TR/html-design-principles/
[NETWORK-ERROR-LOGGING]
Douglas Creager; Ian Clelland. 网络错误日志. 2025年5月5日. WD. URL: https://www.w3.org/TR/network-error-logging/
[RFC7469]
C. Evans; C. Palmer; R. Sleevi. HTTP 公钥钉扎扩展. 2015年4月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc7469

IDL 索引

dictionary ReportBody {
};

dictionary Report {
  DOMString type;
  DOMString url;
  ReportBody? body;
};

[Exposed=(Window,Worker)]
interface ReportingObserver {
  constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options = {});
  undefined observe();
  undefined disconnect();
  ReportList takeRecords();
};

callback ReportingObserverCallback = undefined (sequence<Report> reports, ReportingObserver observer);

dictionary ReportingObserverOptions {
  sequence<DOMString> types;
  boolean buffered = false;
};

typedef sequence<Report> ReportList;

dictionary GenerateTestReportParameters {
  required DOMString message;
  DOMString group = "default";
};

问题索引

本规范未规定报告失败时的重试机制。我们或许需要在此添加,或提供投递失败的指示。↵
如何多态初始化 body?↵
需考虑缓解措施。例如,网络切换时可丢弃报告。[WICG/background-sync Issue #107] ↵
MDN

Report/body

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Report/type

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Report/url

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Report

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportBody

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportingObserver/ReportingObserver

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportingObserver/disconnect

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportingObserver/observe

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportingObserver/takeRecords

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

ReportingObserver

FirefoxNoneSafari16.4+Chrome69+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?