diff --git a/web/src/services/diagnostics/client-diagnostics.ts b/web/src/services/diagnostics/client-diagnostics.ts index f4c37e0d0..8a71b35d1 100644 --- a/web/src/services/diagnostics/client-diagnostics.ts +++ b/web/src/services/diagnostics/client-diagnostics.ts @@ -124,7 +124,7 @@ export function recordDiagnosticEvent(input: DiagnosticEventInput) { category: input.category, code: redactClientText(input.code), message: redactClientText(input.message) || "未命名诊断事件", - route: normalizeRoute(input.route || (typeof window !== "undefined" ? window.location.pathname : "")), + route: normalizeRoute(input.route || browserLocation()?.pathname || ""), durationMs: input.durationMs === undefined ? undefined : clampNumber(input.durationMs, 0, 86_400_000), httpStatus: input.httpStatus === undefined ? undefined : clampNumber(input.httpStatus, 0, 599), requestId: safeDiagnosticId(input.requestId), @@ -177,11 +177,17 @@ function readHeader(headers: unknown, key: string) { return typeof value === "string" ? value : undefined; } +// 诊断只在真实浏览器里有地址。测试与 SSR 环境里 `window` 可能存在但 `window.location` 不存在 +// (bun test 就是这样),所以两个都要探测,不能只看 typeof window。 +function browserLocation(): Location | undefined { + return typeof window !== "undefined" && window.location ? window.location : undefined; +} + function normalizeRoute(value?: string) { const raw = String(value || "").trim(); - if (!raw) return typeof window !== "undefined" ? window.location.pathname : "/"; + if (!raw) return browserLocation()?.pathname || "/"; try { - const parsed = new URL(raw, typeof window !== "undefined" ? window.location.origin : "http://localhost"); + const parsed = new URL(raw, browserLocation()?.origin || "http://localhost"); return parsed.pathname || "/"; } catch { return raw.split(/[?#]/, 1)[0] || "/";