Next.js 动态路由段
Next.js App Router 用 [id]、[...slug]、[[...slug]] 表达动态、Catch-all 与 Optional Catch-all URL segment,并通过 params 取得路径参数。
#concept
#growing
#frame
#react
[!info] related notes
- 所属 MOC:
- 前置概念: nextjs-file-system-routing、routing
- 并列概念:
- 易混淆概念:
- 关系笔记:
Next.js 动态路由段
一句话定义
Next.js 动态路由段允许目录名中使用方括号,把 URL 中某一段或多段路径作为运行时参数交给页面。
最常见形式:
[id] → 一个动态 segment
[...slug] → 一个或多个 segment
[[...slug]] → 零个或多个 segment
单个动态 Segment:[id]
app/
└── assessment/
└── [assessmentId]/
└── page.tsx
可以匹配:
/assessment/123
/assessment/a8f2...
页面通过 params 取得:
export default async function Page({
params,
}: {
params: Promise<{ assessmentId: string }>
}) {
const { assessmentId } = await params
// ...
}
所以:
/assessment/123
↓
assessmentId = "123"
[id]、[slug]、[assessmentId] 的区别
方括号内部名称只是参数名,本质机制相同。
常见语义:
[id]:数据库或领域实体标识。[slug]:更适合人类阅读的 URL 标识,例如react-server-components。[assessmentId]:在多层动态路由中更明确,避免多个id混淆。
Catch-all:[...slug]
app/docs/[...slug]/page.tsx
可以匹配:
/docs/react
/docs/react/hooks
/docs/react/hooks/use-effect
得到的参数通常是数组:
["react"]
["react", "hooks"]
["react", "hooks", "use-effect"]
适合文档、Wiki、CMS、知识库等深度不固定的内容路径。
Optional Catch-all:[[...slug]]
app/shop/[[...slug]]/page.tsx
除了:
/shop/clothing
/shop/clothing/shirts
还可以覆盖没有后续 segment 的:
/shop
因此:
[...slug] → 至少一个 segment
[[...slug]] → 可以没有 segment
多层动态路由
/goals/123/tasks/456
可表示为:
app/
└── goals/
└── [goalId]/
└── tasks/
└── [taskId]/
└── page.tsx
得到:
goalId = "123"
taskId = "456"
URL 层级不是授权证明
一个非常重要的安全边界:
/goals/123/tasks/456
只表示客户端请求了这组标识,不证明 Task 456 一定属于 Goal 123,也不证明当前用户有访问权限。
服务端仍必须验证:
身份认证
↓
资源存在性
↓
Goal / Task 关系
↓
当前用户是否拥有访问权限
否则很容易形成 IDOR / BOLA。
URL 层级和数据库关系不是同一回事
路由可以表达产品的信息架构,但不能让目录结构替代领域约束。
URL nesting
≠
DB foreign-key relation
≠
authorization rule
这三个层面可以相互映射,但必须分别验证。
最短记忆方式
[id] = 一个变量路径段
[...slug] = 一个或多个变量路径段
[[...slug]] = 零个或多个变量路径段
params = 页面取得这些路径值的入口
普通目录如何组成 URL,见 Next.js 文件系统路由。