Next.js中间件运行Prometheus库遇Edge Runtime错误及SSR请求时长追踪
问题场景与报错
用户尝试在Next.js中间件中使用prom-client的Histogram追踪HTTP请求时长,代码如下:
import { Histogram } from 'prom-client'; import { NextRequest, NextResponse } from 'next/server'; const durationHistogram = new Histogram({ name: 'web_app_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'route', 'code'], buckets: [0.1, 0.3, 1.5, 10, 30, 100], }); export function middleware(request: NextRequest) { const stop = durationHistogram.startTimer(); const response = NextResponse.next(); stop({ route: request.nextUrl.pathname, method: request.method, code: response.status }); return response; }
运行时触发错误:
A Node.js API is used (process.uptime) which is not supported in the Edge Runtime.
已知Vercel不会为中间件支持Node.js运行时,需要解决该错误,并了解其他追踪SSR请求时长的方案。
解决方案
一、适配Edge Runtime的Prometheus指标方案
prom-client依赖Node.js专属API(比如process.uptime),没法直接在Edge Runtime使用,有两种替代思路:
1. 改用Edge兼容的指标库
选择专门适配Edge环境的Prometheus指标库,这类库会规避Node.js API,改用Edge Runtime支持的能力实现统计逻辑。
2. 手动实现简易时长统计
直接用Edge支持的performance.now()计算请求时长,自行维护直方图的桶统计逻辑:
import { NextRequest, NextResponse } from 'next/server'; // 定义直方图的时间桶(单位:秒) const buckets = [0.1, 0.3, 1.5, 10, 30, 100]; // 内存中存储统计数据(注意:Edge实例无状态,数据会随实例销毁丢失,需异步上报到外部服务) const histogramStats = { counts: buckets.map(() => 0), totalDuration: 0, }; export function middleware(request: NextRequest) { const startTime = performance.now(); const response = NextResponse.next(); // 异步统计时长(避免阻塞响应返回) setTimeout(() => { const duration = (performance.now() - startTime) / 1000; // 转成秒 histogramStats.totalDuration += duration; // 匹配对应的桶并计数 for (let i = 0; i < buckets.length; i++) { if (duration <= buckets[i]) { histogramStats.counts[i]++; break; } } // 这里可以把统计数据上报到外部监控服务(比如Prometheus网关、Datadog等) }, 0); return response; }
二、其他SSR请求时长追踪方案
除了中间件,还有这些更适合SSR场景的追踪方式:
1. 在App Router的Server Components里统计
直接在Server Component的加载逻辑前后记录时间,精准追踪页面SSR的耗时:
// app/page.tsx export default async function HomePage() { const startTime = performance.now(); // 执行SSR核心逻辑:获取数据、处理业务等 const pageData = await fetchPageData(); const ssrDuration = (performance.now() - startTime) / 1000; // 上报时长到监控服务 reportMetric('ssr_page_duration', ssrDuration, { route: '/', method: 'GET' }); return <div>页面内容:{pageData}</div>; }
2. Pages Router中用自定义App/Document统计
如果用的是Pages Router,可以在_app.tsx或_document.tsx的服务端方法里统计:
// pages/_app.tsx import type { AppProps } from 'next/app'; function MyApp({ Component, pageProps }: AppProps) { return <Component {...pageProps} />; } MyApp.getInitialProps = async (appContext) => { const startTime = performance.now(); const appProps = await App.getInitialProps(appContext); const duration = (performance.now() - startTime) / 1000; // 上报统计数据 reportMetric('ssr_app_duration', duration, { route: appContext.router.pathname, method: appContext.req.method }); return { ...appProps }; }; export default MyApp;
3. 集成第三方监控工具
Next.js支持和Datadog、New Relic这类监控服务商集成,它们的SDK会自动追踪SSR请求时长、资源加载耗时等数据,不用手动写统计代码,只需按文档配置即可。
4. 在API路由中单独统计
如果SSR页面的数据依赖内部API路由,可以在API路由里单独统计接口耗时:
// app/api/data/route.ts export async function GET(request: Request) { const startTime = performance.now(); const apiData = await fetchExternalResource(); const duration = (performance.now() - startTime) / 1000; reportMetric('api_request_duration', duration, { route: '/api/data', method: 'GET' }); return Response.json(apiData); }
内容的提问来源于stack exchange,提问作者africandrogba
相关产品推荐
相关产品推荐

