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

如何在NextJS 12.0的其他函数中访问Express请求?

在Next.js 12中全局获取请求上下文的方案

在Next.js 12里并没有像PHP框架那样直接的全局request()函数,但可以通过以下几种方式实现类似效果,满足日志埋点、请求ID追踪的需求:

1. 用Async Local Storage实现全局请求上下文(Node.js环境)

Next.js 12的Node.js运行时支持Node的async_hooks模块,我们可以用它创建请求上下文容器,在请求进入时保存信息,后续任何异步代码都能取出:

步骤1:创建上下文管理模块

// lib/requestContext.js
const { AsyncLocalStorage } = require('async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

// 保存请求上下文
function setRequestContext(req) {
  const context = {
    requestUrl: req.url,
    referrer: req.headers.referer || '',
    userAgent: req.headers['user-agent'] || '',
    requestId: req.headers['x-request-id'] || generateRequestId() // 自定义生成请求ID
  };
  return asyncLocalStorage.run(context, () => {});
}

// 获取当前上下文(无请求时返回null)
function getRequestContext() {
  return asyncLocalStorage.getStore() || null;
}

// 简单的请求ID生成函数
function generateRequestId() {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

module.exports = { setRequestContext, getRequestContext };

步骤2:在自定义服务器或入口中间件中注入上下文

如果用自定义Express服务器:

// server.js
const express = require('express');
const next = require('next');
const { setRequestContext } = require('./lib/requestContext');

const app = express();
const nextApp = next({ dev: process.env.NODE_ENV !== 'production' });
const handle = nextApp.getRequestHandler();

nextApp.prepare().then(() => {
  app.use((req, res, next) => {
    // 注入请求上下文
    setRequestContext(req);
    next();
  });

  app.all('*', (req, res) => {
    return handle(req, res);
  });

  app.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
  });
});

如果不用自定义服务器,也可以在pages/_app.js的getInitialProps中注入(注意:getInitialProps会让所有页面变为SSR,按需使用):

// pages/_app.js
import { setRequestContext } from '../lib/requestContext';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

MyApp.getInitialProps = async ({ ctx }) => {
  if (ctx.req) {
    setRequestContext(ctx.req);
  }
  return { pageProps: {} };
};

export default MyApp;

步骤3:在日志类中使用

// lib/logger.js
const { getRequestContext } = require('./requestContext');

function log(message) {
  const context = getRequestContext();
  const logData = {
    message,
    timestamp: new Date().toISOString(),
    ...(context ? {
      requestUrl: context.requestUrl,
      referrer: context.referrer,
      userAgent: context.userAgent,
      requestId: context.requestId
    } : {})
  };
  console.log(JSON.stringify(logData));
}

module.exports = { log };

不管是在getServerSideProps、API路由还是自定义中间件里,调用log()都会自动带上请求上下文;无请求场景(比如getStaticProps)下,只会输出基础日志内容。

2. 在getServerSideProps中直接传递请求信息

如果不需要全局上下文,仅在页面SSR逻辑中使用,可以直接在getServerSideProps里提取请求参数,传递给组件或日志函数:

// pages/some-page.js
import { log } from '../lib/logger';

export async function getServerSideProps(ctx) {
  const { req } = ctx;
  const requestContext = {
    requestUrl: req.url,
    referrer: req.headers.referer,
    userAgent: req.headers['user-agent']
  };

  // 直接传入日志函数
  log('Page loaded', requestContext);

  return {
    props: { requestContext } // 也可以传递给组件使用
  };
}

3. Edge Middleware中的处理(Next.js 12 Edge Runtime)

如果使用Next.js 12的Edge Middleware(middleware.js),由于Edge Runtime不支持Node的async_hooks,可以通过NextResponse传递请求ID,或直接在Middleware中处理日志:

// middleware.js
import { NextResponse } from 'next/server';

export function middleware(req) {
  const requestId = req.headers.get('x-request-id') || generateRequestId();
  const response = NextResponse.next();
  
  // 把请求ID设置到响应头,后续API路由或页面可读取
  response.headers.set('x-request-id', requestId);

  // 直接记录日志
  console.log({
    message: 'Request received',
    requestUrl: req.url,
    referrer: req.headers.get('referer'),
    userAgent: req.headers.get('user-agent'),
    requestId
  });

  return response;
}

function generateRequestId() {
  return crypto.randomUUID(); // Edge Runtime原生支持crypto模块
}

在Edge环境的API路由或getServerSideProps里,可通过req.headers.get('x-request-id')获取请求ID,其他请求信息也能直接从req对象提取。

注意:getStaticProps在构建阶段运行,确实没有请求上下文,此时getRequestContext()会返回null,日志不会包含请求相关字段,符合需求。

内容的提问来源于stack exchange,提问作者Kristi Jorgji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:15:58