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

NextJS生产环境中ISR页面访问时Middleware多次触发问题

Next.js生产环境下Middleware重复调用问题的排查与解决

我有一个NextJS应用,托管着从Supabase获取数据的ISR页面,配置了用于页面渲染前记录访问的Middleware,代码如下:

export async function middleware(
  request: NextRequest,
  fetchEvent: NextFetchEvent
) {
  console.log('request.nextUrl.pathname', request.nextUrl.pathname);
  if (request.nextUrl.pathname.split('/').length === 2) {
    return linkVisitMiddleware(request, fetchEvent);
  }
}

问题是生产环境(next start)中该Middleware会被调用2-3次,服务器日志重复打印request.nextUrl.pathname /slug;但本地环境(next serve)下仅执行一次,符合预期。调整reactStrictMode无效,已在NextJS 13.1.1、13.1.6和13.3.0版本中测试过该问题。

可能的原因

  1. ISR重新验证触发额外请求:ISR页面在触发重新验证(revalidate)时,Next.js会发起后台请求重新生成页面,这会额外触发一次Middleware。如果访问时机刚好赶上页面重新验证周期,就会出现多次调用。
  2. 静态资源请求误匹配:生产环境中浏览器会自动请求/favicon.ico、/robots.txt等资源,这些路径按split('/').length === 2的判断逻辑会被误识别为目标路由,导致Middleware重复执行。
  3. Next.js生产环境预取机制:生产环境下Next.js可能会对路由进行预取操作,预取请求也会触发Middleware。

解决方案

1. 精准匹配目标路由

放弃通过路径分割长度判断的方式,改用Next.js提供的matchPath工具函数精准匹配ISR页面路由(假设你的ISR页面路由为/[slug]):

import { matchPath } from 'next/router';
import { NextResponse } from 'next/server';

export async function middleware(
  request: NextRequest,
  fetchEvent: NextFetchEvent
) {
  console.log('request.nextUrl.pathname', request.nextUrl.pathname);
  // 仅匹配/[slug]格式的页面路由
  if (matchPath('/[slug]', request.nextUrl.pathname)) {
    return linkVisitMiddleware(request, fetchEvent);
  }
  return NextResponse.next();
}

2. 排除静态资源与后台请求

在Middleware中添加过滤逻辑,排除静态资源、API请求以及ISR重新验证的后台请求:

import { NextResponse } from 'next/server';

export async function middleware(
  request: NextRequest,
  fetchEvent: NextFetchEvent
) {
  const pathname = request.nextUrl.pathname;
  console.log('request.nextUrl.pathname', pathname);

  // 排除静态资源、API、robots.txt等非页面请求
  const excludeList = [
    '/favicon.ico',
    '/robots.txt',
    '/sitemap.xml',
    '/api/',
    '/_next/' // 排除Next.js自身的静态资源路径
  ];
  if (excludeList.some(item => pathname.startsWith(item))) {
    return NextResponse.next();
  }

  // 排除ISR重新验证的后台请求
  if (request.headers.get('x-nextjs-revalidate')) {
    return NextResponse.next();
  }

  if (pathname.split('/').length === 2) {
    return linkVisitMiddleware(request, fetchEvent);
  }
  return NextResponse.next();
}

3. 在记录逻辑中去重

如果上述方法仍无法解决,可以在linkVisitMiddleware中通过请求的唯一标识(比如用户IP+路径+时间戳)做去重处理,避免重复记录访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 14:18:17