访问ISR页面时多次调用NextJS中间件

piah890a  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(149)

我有一个NextJS应用程序,它承载一个从Supabase获取数据的ISR页面,有一个中间件在呈现页面之前记录页面访问。

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);
  }
}

中间件的问题被调用了2到3次(不知道为什么这些数字会波动)。
上述日志记录将在服务器上打印以下内容:

request.nextUrl.pathname /slug
request.nextUrl.pathname /slug
request.nextUrl.pathname /slug

奇怪的是,这只发生在生产环境(next start)中。在本地(next serve),它按预期运行一次。
我看到了一些关于reactStrictMode的文章,但这并没有帮助:(
编辑:
在NextJS 13.1.113.1.613.3.0上测试

vxf3dgd4

vxf3dgd41#

经过几个小时的调试,我找到了罪魁祸首。
ISR页面使用回退策略,如{fallback: true},因此,它尝试请求HTML页面,如果不可用,它将再次访问相同的路由来获取数据。
为了避免这个问题,我发现NextJS使用头来区分请求的类型。下面是我的解决方案:

import { linksMiddleware } from 'middleware/links';
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';

export async function middleware(
  request: NextRequest,
  fetchEvent: NextFetchEvent
) {
  // These methods are used when accessing locale routes, so we discard them
  if (request.method === 'OPTIONS' || request.method === 'HEAD') {
    return NextResponse.next();
  }

  //Capture URL locale (if any) and id. For example: /ar/random-id or /random-id
  const pathParams = request.nextUrl.pathname.split('/');

  if (pathParams.length === 2 && isDataRequest(request)) {
    // This means that we are accessing the entity homepage
    return linksMiddleware(request, fetchEvent, 'entity');
  }

  return NextResponse.next();
}

export const config = {
  matcher: [
    // This is to prevent the middleware from running on the API routes and during development
    '/((?!api|_next/static|_next/image|favicon.ico|favicon.svg).*)',
  ],
};

/**
 * Check if the request is a data request for cases of fallback pages
 * This header is absent in the initial request
 */
const isDataRequest = (request: NextRequest): boolean =>
  request.headers.get('x-nextjs-data') === '1' ||
  // The header is absent in development mode since there's no fallback logic (SSR-like)
  process.env.NODE_ENV === 'development';

此外,我还添加了一个HTTP方法检查,用于区域设置路由的情况,不包括OPTIONSHEAD

相关问题