You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:01:07