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

如何在Next.js Edge运行时用@vercel/otel和register()监控中间件请求响应

Next.js Edge中间件全局追踪请求/响应方案

背景与约束

  • Next.js 15.2+中,中间件默认运行在Edge Runtime,实验性Node.js Runtime不建议用于生产环境
  • 使用next dev --turbopack启动时,instrumentation.ts执行在nodejs Runtime,中间件执行在edge Runtime
  • @vercel/otel是Edge Runtime唯一原生支持的OpenTelemetry方案,Node SDK完全不兼容Edge环境

实现步骤

1. 分Runtime初始化追踪逻辑

在instrumentation.ts中针对不同Runtime加载对应逻辑,避免跨环境错误:

import { trace } from '@opentelemetry/api';
import { NextResponse } from 'next/server';

export function register() {
  // Node Runtime:仅初始化Node SDK(用于非Edge服务端逻辑,可选)
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { NodeSDK } = require('@opentelemetry/sdk-node');
    const sdk = new NodeSDK({
      serviceName: 'your-service-name',
      // 配置Collector地址与导出器
    });
    sdk.start();
  }

  // Edge Runtime:扩展@vercel/otel实现中间件追踪
  if (process.env.NEXT_RUNTIME === 'edge') {
    const { registerOTel } = require('@vercel/otel');
    registerOTel({
      serviceName: 'your-service-name',
      traceExporter: {
        type: 'otlp',
        url: 'http://localhost:4318/v1/traces', // 对应你的Collector地址
      },
      instrumentations: [
        {
          name: 'custom-nextjs-middleware',
          setup() {
            // 拦截Request构造,捕获请求元数据
            const OriginalRequest = globalThis.Request;
            globalThis.Request = class extends OriginalRequest {
              constructor(input, init) {
                super(input, init);
                const activeSpan = trace.getActiveSpan();
                if (activeSpan) {
                  activeSpan.setAttributes({
                    'request.method': this.method,
                    'request.url': this.url,
                    'request.headers': JSON.stringify(Object.fromEntries(this.headers)),
                  });
                }
              }
            };

            // 拦截NextResponse.next,捕获响应元数据
            const originalNext = NextResponse.next;
            NextResponse.next = function (...args) {
              const response = originalNext.apply(this, args);
              const activeSpan = trace.getActiveSpan();
              if (activeSpan) {
                activeSpan.setAttributes({
                  'response.status': response.status,
                  'response.headers': JSON.stringify(Object.fromEntries(response.headers)),
                });
              }
              return response;
            };

            // 可按需扩展拦截NextResponse.redirect、rewrite等方法
          },
        },
      ],
    });
  }
}

2. 配置Next.js钩子(兼容旧版本)

Next.js 15+无需额外配置,为兼容13.4-14版本,在next.config.js中添加:

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    instrumentationHook: true,
  },
};

module.exports = nextConfig;

3. 验证追踪效果

  • 启动opentelemetry-collector-dev-setup接收追踪数据
  • 在任意中间件中添加调试代码,确认Span关联:
import { trace } from '@opentelemetry/api';

export function middleware(request) {
  const span = trace.getActiveSpan();
  console.log('Current middleware span:', span?.spanContext());
  return NextResponse.next();
}
  • 查看Collector中的Span数据,确认每个中间件的请求/响应属性已被捕获

核心注意事项

  • 禁止在Edge Runtime中导入Node SDK,会直接触发运行时错误
  • 自定义插桩逻辑需保持原有API行为,仅追加追踪属性,避免破坏业务逻辑
  • 生产环境需确保@vercel/otel版本与Next.js版本匹配,优先使用最新稳定版

内容的提问来源于stack exchange,提问作者Brendan Hoskins

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:23:16