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

Next.js 13 App目录动态路由匹配无效时返回404的方案咨询

解决Next.js 13.4.4 App目录+next-intl下动态路由404不生效问题

针对你遇到的问题,以下是几种比组件内单独调用notFound()更优的实现方式:

1. 确保generateStaticParams生成完整多语言路径组合(推荐)

App目录下dynamicParams: false生效的核心前提是,generateStaticParams必须生成所有包含多语言前缀的有效路由参数组合——因为next-intl的路由结构是[locale]/post/[slug],参数是locale和slug的绑定组合,少了任何一个都会导致Next.js无法正确识别无效路径。

示例代码(app/[locale]/post/[slug]/page.tsx):

import { notFound } from 'next/navigation';
import { getPosts, getPostBySlugAndLocale } from '@/lib/posts';
import { locales } from '@/i18n.config';

// 禁用动态参数,未预生成的路径直接返回404
export const dynamicParams = false;

// 生成所有有效locale+slug的参数组合
export async function generateStaticParams() {
  const posts = await getPosts();
  return locales.flatMap(locale => 
    posts.map(post => ({
      locale,
      slug: post.slug
    }))
  );
}

async function Page({ params }: { params: { locale: string; slug: string } }) {
  // 兜底校验(防止预生成时的遗漏)
  const post = await getPostBySlugAndLocale(params.slug, params.locale);
  if (!post) notFound();

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  );
}

export default Page;

如果你的generateStaticParams已经正确生成完整组合但仍不生效,可能是next-intl的路由配置干扰了Next.js的静态路径匹配,可以结合下面的Middleware方案。

2. 用Middleware提前拦截无效路由

通过Next.js的Middleware在请求到达页面组件前就校验路径有效性,直接返回404,避免组件层面的冗余逻辑,性能更优。

示例代码(middleware.ts):

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { locales } from './i18n.config';
import { checkPostExists } from '@/lib/posts';

export async function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname;
  // 匹配多语言文章路由(如/en/post/foo、/zh/post/bar)
  const routeMatch = pathname.match(/^\/([a-z]{2})\/post\/([^\/]+)$/);

  if (routeMatch) {
    const [, locale, slug] = routeMatch;
    // 校验语言是否合法
    if (!locales.includes(locale)) {
      return new NextResponse('Not Found', { status: 404 });
    }
    // 校验文章是否存在
    const postExists = await checkPostExists(slug, locale);
    if (!postExists) {
      return new NextResponse('Not Found', { status: 404 });
    }
  }

  return NextResponse.next();
}

// 指定Middleware生效的路径范围
export const config = {
  matcher: ['/([a-z]{2})/post/:path*'],
};

3. 优化组件内的notFound校验逻辑

如果坚持用组件内校验,可以把校验逻辑抽成可复用的Server Component,让页面代码更简洁:

// app/[locale]/post/[slug]/PostNotFoundGuard.tsx
'use server';

import { notFound } from 'next/navigation';
import { getPostBySlugAndLocale } from '@/lib/posts';

export async function PostNotFoundGuard({ locale, slug }: { locale: string; slug: string }) {
  const post = await getPostBySlugAndLocale(slug, locale);
  if (!post) notFound();
  return null;
}

在页面组件中引入:

import { PostNotFoundGuard } from './PostNotFoundGuard';
import { getPostBySlugAndLocale } from '@/lib/posts';

async function Page({ params }: { params: { locale: string; slug: string } }) {
  // 先执行校验,无效则直接返回404
  await PostNotFoundGuard(params);
  const post = await getPostBySlugAndLocale(params.slug, params.locale);

  return <article>{/* 渲染文章内容 */}</article>;
}

export const dynamicParams = false;
export async function generateStaticParams() { /* 同上 */ }

export default Page;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 20:22:49