Copyright © 2023 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范使服务器能够向用户代理传达有关请求-响应周期的性能指标。它还标准化了一个 JavaScript 接口,使应用程序能够收集、处理并根据这些指标进行优化,以提升应用交付效率。
本节描述了本文档在发布时的状态。当前 W3C 公布的技术文档和本技术报告的最新修订版可在 W3C 技术报告索引(https://www.w3.org/TR/)中找到。
本文档由 Web 性能工作组 作为工作草案在 推荐轨道上发布。
作为工作草案发布并不意味着获得 W3C 及其成员的认可。
本文档为草稿版本,可能随时被更新、替换或废弃。除作为在研成果外,不应引用本文件。
本文档由在 W3C 专利政策 下运作的工作组编写。 W3C 维护着与工作组交付物相关的 专利披露公开列表;该页面还包括披露专利的说明。任何个人若实际知晓某项专利且认为其包含必要权利要求,必须依照《W3C 专利政策》第 6 节进行披露。
本文档受 2021 年 11 月 2 日 W3C 流程文件管理。
本节为非规范性内容。
准确衡量 Web 应用程序的性能特征是提升 Web 应用速度的重要方面。[NAVIGATION-TIMING] 和 [RESOURCE-TIMING] 为文档及其资源提供了详细的请求计时信息,包括请求发起的时间、协商连接和接收响应的各个关键节点。然而,虽然用户代理可以观察到这些请求的时序数据,但它无法了解请求-响应周期中某些阶段为何以及如何花费了如此多的时间,例如请求是如何路由的、服务器端的时间分布等。
本规范引入了 PerformanceServerTiming
接口,使服务器能够向用户代理传达有关请求-响应周期的性能指标,并通过 JavaScript 接口使应用能够收集、处理和利用这些指标,从而优化应用交付。
本规范中,除标记为非规范性的部分外,所有创作指南、图表、示例和注释均为非规范性内容。规范中的其他内容均为规范性内容。
本文档中的关键词 MAY(可以)、MUST(必须)和 SHOULD NOT(不应)应按照 BCP 14 [RFC2119] [RFC8174] 的定义进行解释,仅当这些词全部大写时才具有规范性含义,如本处所示。
Server-Timing 头字段用于在给定的请求-响应周期中传递一个或多个指标和描述。RFC5234 中给出的 ABNF(扩展巴科斯-诺尔范式)语法如下:
Server-Timing = #server-timing-metric
server-timing-metric = metric-name *( OWS ";" OWS server-timing-param )
metric-name = token
server-timing-param = server-timing-param-name OWS "=" OWS server-timing-param-value
server-timing-param-name = token
server-timing-param-value = token / quoted-string
有关 #
、*
、OWS
、token
和 quoted-string
的定义,请参见 RFC7230。
一个响应 可以包含多个具有相同 metric-name 的 server-timing-metric 条目,且用户代理必须处理并公开所有这些条目。
用户代理可以以任意顺序呈现提供的指标——即 HTTP 头字段中指标的顺序无关紧要。
该头字段具有可扩展语法,以支持将来添加参数。对于响应的 Server-Timing 头字段中未识别的 server-timing-param-name,用户代理必须忽略这些标记并继续处理,而不是报告错误。
为避免歧义,单个server-timing-param-name
不应在同一个server-timing-metric
中出现多次。如果指定了多次,仅考虑第一次出现,即使该server-timing-param
不完整或无效。所有后续出现必须被忽略,不得报告错误或以其他方式更改server-timing-metric
的处理。这是参数顺序唯一有意义的情形。
用户代理必须忽略server-timing-param-value
后、下一个server-timing-param
和当前server-timing-metric
结尾之前出现的多余字符。
用户代理必须忽略metric-name
后、首个server-timing-param
和下一个server-timing-metric
之前出现的多余字符。
本规范为 server-timing-param-names "dur"(用于duration
)和 "desc"(用于description
)建立
server-timing-params,二者均为可选。
为减少 HTTP 开销,应尽可能缩短名称和描述——例如使用缩写,并在可行时省略可选值。
由于无法保证客户端、服务器和中间设备间时钟同步,因此无法将有意义的startTime
映射到客户端时间轴。因此,本规范特意省略了任何startTime
属性。如果开发者希望建立多个条目的关联,可以通过指标名称和/或描述传递自定义数据。
服务器和/或相关中间设备完全控制向用户代理传递哪些指标以及何时传递。例如,出于隐私或安全原因,某些指标的访问可能受限——见6. 隐私与安全部分。
要解析 Server-Timing 头字段,给定字符串 field:
令 position 为 位置变量,初始指向 field 的起始处。
令 name 为从 field 收集、且不等于 U+003B (;) 的一串码点的结果,基于 position。
如果 name 为空字符串,则返回 null。
令 metric 为新的 PerformanceServerTiming
,其指标名称为 name。
令 params 为一个空的有序映射。
当 position 未到达 field 末尾时:
position 前进 1。
令 paramName 为从 field 收集、且不等于 U+003D (=) 的一串码点的结果,基于 position。
去除 paramName 首尾的 ASCII 空白字符。
如果 paramName 为空字符串,或 params[paramName] 已存在,则继续。
position 前进 1。
令 paramValue 为空字符串。
在 field 中跳过 position 处的 ASCII 空白字符。
如果 field 的 position 处码点为 U+0022 ("),则:
将 paramValue 设为收集 HTTP 引号字符串的结果,参数为 field 和 position,extract-value 标志已设置。
从 field 收集、且不等于 U+003B (;) 的一串码点,基于 position。结果不使用。
否则:
令 rawParamValue 为从 field 收集、且不等于 U+003B (;) 的一串码点的结果,基于 position。
将 paramValue 设为 rawParamValue 去除首尾 ASCII 空白后的结果。
将 metric 的参数设为 params。
返回 metric。
WebIDL[Exposed=(Window,Worker)]
interface PerformanceServerTiming
{
readonly attribute DOMString name
;
readonly attribute DOMHighResTimeStamp duration
;
readonly attribute DOMString description
;
[Default] object toJSON
();
};
当调用 toJSON
时,执行 [WEBIDL] 的默认 toJSON 步骤。
duration
getter 步骤如下:
如果 dur 为错误,则返回 0;否则返回 dur。
由于 duration
是 DOMHighResTimeStamp
,
它通常表示以毫秒为单位的持续时间。但实际上无法强制执行,duration
可以表示任何时间单位,建议使用毫秒。
description
getter 步骤为:如果 this 的 params["desc"
] 存在,则返回该值,否则返回空字符串。
PerformanceServerTiming
具有一个关联的字符串 指标名称,初始值为空字符串。
PerformanceServerTiming
具有一个关联的有序映射 params,初始为空。
PerformanceResourceTiming
接口的扩展PerformanceResourceTiming
接口(本规范部分扩展)定义于 [RESOURCE-TIMING]。
WebIDL[Exposed=(Window,Worker)]
partial interface PerformanceResourceTiming
{
readonly attribute FrozenArray<PerformanceServerTiming
> serverTiming
;
};
serverTiming
getter 步骤如下:
令 entries 为新的列表。
对每个 field,在 this 的 timing info 的 server-timing headers 中:
返回 entries。
本节为非规范性内容。
本规范定义的接口会将潜在敏感的应用和基础设施信息暴露给所有包含了带有服务器计时指标的资源的网页。因此,默认情况下,对 PerformanceServerTiming
接口的访问受到同源策略的限制。资源提供方可以通过添加
[RESOURCE-TIMING] 中定义的 Timing-Allow-Origin
HTTP
响应头明确允许服务器计时信息被访问,该响应头指定了哪些域可以访问服务器指标,但用户代理可以继续保留同源策略限制。
除了使用 Timing-Allow-Origin
HTTP
响应头外,服务器还可以通过相关逻辑控制返回哪些指标、何时返回以及返回给谁——例如,服务器可以只为已正确认证的用户提供某些指标,对其他用户则完全不提供。
永久消息头字段注册表应根据以下信息进行更新([RFC3864]):
本节为非规范性内容。
> GET /resource HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< Server-Timing: miss, db;dur=53, app;dur=47.2
< Server-Timing: customView, dc;desc=atl
< Server-Timing: cache;desc="Cache Read";dur=23.2
< Trailer: Server-Timing
< (... snip response body ...)
< Server-Timing: total;dur=123.4
名称 | 耗时 | 描述 |
---|---|---|
miss | ||
db | 53 | |
app | 47.2 | |
customView | ||
dc | atl | |
cache | 23.2 | Cache Read |
total | 123.4 |
上述头字段传递了六个不同的指标,展示了服务器向用户代理传递数据的所有可能方式:仅指标名、带数值的指标、带数值和描述的指标,以及带描述的指标。例如,对于
example.com/resource.jpg
的抓取,上述指标可能表示:
应用程序可以通过提供的 JavaScript 接口收集、处理并利用这些指标:
// serverTiming 条目可存在于 'navigation' 和 'resource' 类型的条目上
for (const entryType of ['navigation', 'resource']) {
for (const {name: url, serverTiming} of performance.getEntriesByType(entryType)) {
// 遍历 serverTiming 数组
for (const {name, duration, description} of serverTiming) {
// 只关注“慢”的条目
if (duration > 200) {
console.info('Slow server-timing entry =',
JSON.stringify({url, entryType, name, duration, description}, null, 2))
}
}
}
}
本节为非规范性内容。
服务器处理时间可能占总请求时间的很大一部分。例如,一个动态响应可能需要一次或多次数据库查询、缓存查找、API 调用、处理相关数据和渲染响应的时间等。同样,即使是静态响应,也可能由于服务器过载、缓存缓慢或其他原因而被延迟。
目前,用户代理的开发者工具能够显示请求发起的时间,以及响应的首字节和末字节被接收的时间。然而,开发者无法看到服务器端时间的分布方式或花费在哪里,这意味着难以及时诊断服务器性能瓶颈及其所在组件。为了解决这个问题,开发者通常需要使用不同的技巧:查看服务器日志、在响应中嵌入性能数据(如果可能)、使用外部工具等。这使得定位和诊断性能瓶颈变得困难,甚至在很多情况下不可行。
Server Timing 定义了一种标准机制,使服务器能够将相关性能指标传递给客户端,并允许客户端直接在开发者工具中展示这些信息——例如,请求可以被服务器发送的指标注释,以便洞察响应生成过程中时间的花费和分布情况。
除了在开发者工具中展示服务器发送的性能指标外,标准 JavaScript 接口还使分析工具能够自动收集、处理、上报和聚合这些指标,用于运维和性能分析。
Server Timing 使源服务器能够传递关于处理请求过程中时间分布位置和方式的性能指标。然而,同一请求和响应也可能经过一个或多个代理(例如缓存服务器、负载均衡器等),每个代理都可能引入自己的延迟,并希望报告相关性能指标。
例如,CDN 边缘节点可能希望报告使用了哪个数据中心,资源是否存在于缓存中,从缓存或源服务器检索响应所耗时间等。此外,这一过程还可能被其他代理重复,从而实现对请求路由及时间消耗的端到端可见性。
同样地,当 Service Worker 处于激活状态时,部分或全部导航和资源请求都可能经其路由。本质上,激活的 Service Worker 是一个本地代理,能够重新路由请求、提供缓存响应、合成响应等。因此,Server Timing 使 Service Worker 能够报告有关请求处理方式的自定义性能指标:如是从服务器获取还是本地缓存返回,各处理步骤所耗时等。
本节为非规范性内容。
本文档在遵循相关规范许可的前提下,复用了 [NAVIGATION-TIMING]、[RESOURCE-TIMING]、[PERFORMANCE-TIMELINE-2] 和 [RFC6797] 规范中的部分内容。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: