观察一条现有的 Next.js 路由
本示例用于现有 Next.js App Router 应用,请使用已安装最新补丁的当前版本及受支持的 Node.js 部署。after API 自 Next.js 15.1 起稳定;这个 API 最低版本并不表示建议安装未修补的旧版本。它观察处理器返回 Response 或抛出的情况,不代表浏览器收到响应、流式响应完成或后台业务任务完成。
修改路由之前
选择你控制的路由及已获授权、可安全执行的操作。保留认证、校验和业务逻辑。TELEMETRY_API_KEY 只放在服务器环境中,不要使用 NEXT_PUBLIC_ 前缀。首页匿名密钥可发送和查询;账户密钥在验证时需要 read-and-write 权限。只发送事件的应用可使用仅摄取密钥。
添加服务器辅助函数
保存为 lib/with-telemetry.js。使用不含客户标识符的固定路由模板。生成的调用 ID 仅标识一次处理器调用,不代表用户或逻辑任务。不发送 URL、请求体、Cookie、请求头或错误信息。
import { after } from 'next/server';
import { randomUUID } from 'node:crypto';
function warnTelemetry(message) {
try {
console.warn(message);
} catch {
// Diagnostic failure must not change the application outcome.
}
}
export function withTelemetry(handler, routeTemplate) {
return async function observedHandler(request, context) {
const started = performance.now();
const invocationId = randomUUID();
let outcome = 'threw';
let statusCode = null;
try {
const response = await handler(request, context);
outcome = 'returned_response';
statusCode = response.status;
return response;
} finally {
const event = {
invocation_id: invocationId,
route_template: routeTemplate,
method: request.method,
handler_outcome: outcome,
status_code: statusCode,
latency_ms: performance.now() - started,
environment: process.env.NODE_ENV || 'development',
};
try {
after(async () => {
const key = process.env.TELEMETRY_API_KEY;
if (!key) {
warnTelemetry('Telemetry key missing; event not sent');
return;
}
try {
const response = await fetch('https://api.telemetry.sh/log', {
method: 'POST',
headers: {
Authorization: `Bearer ${key}`,
'Content-Type': 'application/json',
},
cache: 'no-store',
signal: AbortSignal.timeout(2000),
body: JSON.stringify({ table: 'nextjs_route_observed', data: event }),
});
if (!response.ok) warnTelemetry('Telemetry event send rejected');
} catch {
warnTelemetry('Telemetry event send failed');
}
});
} catch {
warnTelemetry('Telemetry background scheduling failed');
}
}
};
}
包装现有处理器
将现有导出的 GET 函数改名为 existingGET,保持函数体不变,再导出下方包装器。按实际路由调整方法和固定模板;不要通过新建始终成功的虚构处理器完成设置。
import { withTelemetry } from "@/lib/with-telemetry";
export const GET = withTelemetry(existingGET, "/api/reports/:id");
验证实际调用
通过应用执行获授权的操作,再查询 Telemetry 表。核对路由、方法、时间、结果和状态是否对应刚才的操作。HTTP 接收不等于验证。离线测试、演示路由或代理 QA 运行不是客户集成;虚构发送应使用 telemetry_quickstart。
SELECT invocation_id, route_template, method, handler_outcome,
status_code, latency_ms, environment, timestamp_utc
FROM nextjs_route_observed
WHERE timestamp_utc >= now() - INTERVAL '15 minutes'
ORDER BY timestamp_utc DESC
LIMIT 20;
不保证什么
Next.js after 在响应结束后调度发送。它不是持久队列:平台时限、关机、超时和网络故障可能造成事件丢失。发送超时为两秒,警告为不含私密数据的固定文本;不承诺自动重试或去重。保留现有日志,必需的审计记录应使用持久投递路径。
latency_ms 到处理器返回或抛出时结束,不含事件发送时间。returned_response 也可能是 4xx 或 5xx。threw 可能是框架重定向或控制流,不能自动当作服务器故障。缺少密钥或遥测失败不得替换原响应或原异常。上线前在自己的运行环境中检查此函数。
框架参考与后续步骤
Next.js after 参考文档说明版本及部署支持。不支持静态导出;适配器需要明确支持。响应保留、抛出的异常及遥测发送失败已在隔离的 Next.js 16.3.8 开发模式 App Router 应用中检查,事件发送被拦截且外部网络已禁用。这不验证真实的 Telemetry 摄入或你的生产主机。继续阅读事件摄入验证及 JavaScript SDK 指南以扩展埋点。