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

NextJS 14可选Catch-all Segments动态路由:前置可选slug配置失效求助

实现可选路由段前置、固定段后置的Next.js路由

Next.js的文件系统路由规则明确要求:catch-all(包括可选catch-all)必须作为路由的最后一段,所以你之前尝试的目录结构会触发错误。要实现/category1?/category2?/category3?/category4?/c/categoryId的URL模式,可以通过路由重写的方式实现,以下是两种可行方案:

方案一:App Router 用 Middleware 重写路由

步骤1:创建路由中间件

在项目根目录或app目录下创建middleware.ts,匹配目标URL格式并进行重写:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const url = request.nextUrl;
  // 匹配最多4个前置可选段的URL格式
  const pathMatch = url.pathname.match(/^\/(([^/]+\/){0,3}[^/]+)?\/c\/([^/]+)$/);
  
  if (pathMatch) {
    // 提取前置分类段和categoryId
    const rawCategories = pathMatch[1]?.split('/').filter(Boolean) || [];
    const categoryId = pathMatch[3];
    
    // 限制前置段最多4个,超出则返回404
    if (rawCategories.length > 4) {
      return new NextResponse('Invalid URL', { status: 404 });
    }
    
    // 重写到内部路由 /c/[categoryId]/[[...categories]]
    return NextResponse.rewrite(
      new URL(`/c/${categoryId}/${rawCategories.join('/')}`, request.url)
    );
  }
  
  return NextResponse.next();
}

// 指定中间件作用范围(排除静态资源和API)
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

步骤2:创建内部处理路由

按照以下目录结构创建页面文件:

- app
  - c
    - [categoryId]
      - [[...categories]]
        - page.tsx

步骤3:在页面中处理参数

在page.tsx中获取并使用路由参数:

export default function CategoryPage({
  params,
}: {
  params: {
    categoryId: string;
    categories?: string[];
  };
}) {
  const categories = params.categories || [];
  
  return (
    <div>
      <h2>分类ID:{params.categoryId}</h2>
      <p>前置分类层级:{categories.length > 0 ? categories.join(' > ') : '无'}</p>
    </div>
  );
}

方案二:Page Router 用 next.config.js 配置重写

如果你使用的是Page Router,可以通过next.config.js的rewrites配置实现相同效果:

步骤1:配置重写规则

修改next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        // 匹配带前置可选段的URL
        source: '/:categories*/c/:categoryId',
        // 重写到内部路由
        destination: '/c/:categoryId/:categories*',
      },
    ];
  },
};

module.exports = nextConfig;

步骤2:创建处理页面

在pages目录下创建路由文件:

- pages
  - c
    - [categoryId]
      - [[...categories]].tsx

步骤3:页面中处理参数

在[[...categories]].tsx中获取参数:

import { useRouter } from 'next/router';

export default function CategoryPage() {
  const router = useRouter();
  const { categoryId, categories } = router.query;
  const categoryList = Array.isArray(categories) ? categories : [];
  
  // 限制前置段最多4个
  if (categoryList.length > 4) {
    return <div>无效的URL格式</div>;
  }
  
  return (
    <div>
      <h2>分类ID:{categoryId}</h2>
      <p>前置分类层级:{categoryList.join(' > ') || '无'}</p>
    </div>
  );
}

两种方案都能让用户访问/a/c/123、/a/b/c/456、/a/b/c/d/789这类符合要求的URL,同时内部通过重写路由来处理参数,完美适配你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:41:22