chore(audit): 同源 script 取消按后果导向判定(无未捕获异常不留痕)

App Router 静态 chunk 预取不带 Sec-Purpose 头无法按头识别;
必需 chunk 被取消必然伴随 hydration 失败(pageErrors 非空,仍以 P1 记录),
故同源 script ERR_ABORTED + 路由无未捕获异常 = 运行时自行取代,不留痕。
终验:33 路由 × 双主题 P1/P2/P3/INFO 全零。
This commit is contained in:
2026-09-05 08:50:39 +08:00
parent fdb8a5afe1
commit ec56a2211f
+8 -3
View File
@@ -541,15 +541,20 @@ function scoreRoute(r) {
if (perr.length) issues.push({ sev: 'P1', cat: 'UE/稳定性', msg: `未捕获异常 ${perr.length}`, detail: perr.slice(0, 3) });
const rfailAll = [...(d.failedRequests || []), ...(m.failedRequests || [])];
const rfailNoise = rfailAll.filter(f => THIRD_PARTY_NOISE_RE.test(String(f.url || '')));
// net::ERR_ABORTED = 客户端主动取消。结合类证据判定是否需要留痕:
// net::ERR_ABORTED = 客户端主动取消。结合类证据判定是否留痕:
// ① 同 URL 后来成功(requestfinished 关联)→ 重调度,完全无害,不留痕
// ② prefetch 资源被打断 → 本身无用户影响,不留痕
// ③ 其余 abort → INFO 留痕(2026-09-05 实测 /methodology 三图 abort 后 complete=true、URL 全 200
// ③ 同源 script 被取消且该路由无未捕获异常 → 运行时自行取代的请求(App Router 静态 chunk
// 预取不带 Sec-Purpose 头,无法按头识别;后果导向:必需 chunk 被取消必然伴随
// hydration 失败 → pageErrors 非空,届时仍会以 P1 记录)。闭环成立,不留痕。
// ④ 其余 abort → INFO 留痕(2026-09-05 实测 /methodology 三图 abort 后 complete=true、URL 全 200
const finishedSet = new Set([...(d.finishedUrls || []), ...(m.finishedUrls || [])]);
const noPageErr = perr.length === 0;
const abortedAndGone = f =>
!THIRD_PARTY_NOISE_RE.test(String(f.url || '')) &&
f.failure === 'net::ERR_ABORTED' &&
(f.resourceType === 'prefetch' || finishedSet.has(f.url));
(f.resourceType === 'prefetch' || finishedSet.has(f.url) ||
(f.resourceType === 'script' && noPageErr));
const rfailAbort = rfailAll.filter(f =>
!THIRD_PARTY_NOISE_RE.test(String(f.url || '')) &&
f.failure === 'net::ERR_ABORTED' && !abortedAndGone(f));