type
Post
status
Published
date
Dec 20, 2025
slug
nextjs-003
summary
04 - Routing & Page Rendering - Deep Dive
tags
Next.js
category
编程学习
icon
password
001 Module Introduction
002 Project Setup, Overview & An Exercise!
一、项目初始化与环境配置
- 项目获取与依赖安装
- 课程提供演示项目,可从附件下载,解压后执行
npm install安装所有依赖 - 依赖安装完成后,通过
npm run dev启动Next.js开发服务器,访问localhost:3000查看项目效果
- 初始项目结构解析(假设已掌握Next.js基础结构,重点说明核心文件/文件夹)
- app文件夹:仅含
icon.jpeg,Next.js会自动将其作为页面fav图标,无需额外配置 - 全局CSS文件:包含课程所需基础样式,可自定义修改以调整应用外观
- 布局文件:负责设置页面元数据(如标题、描述),并提供页面基础外壳(如公共头部/底部)
- 首页page.js:结构简洁,无复杂逻辑,作为项目起始页面
二、核心实操任务(基础路由与组件开发)
1. 页面开发任务(2个核心页面)
页面路径 | 功能需求 | 关键技术点 |
/news | 显示可点击的假新闻列表(无需真实数据),新闻项以链接形式呈现 | 1. Next.js文件路由规则(在app文件夹下创建news文件夹及page.js)<br>2. 使用 next/link组件实现页面跳转 |
/news/[id] | 新闻详情页,URL含新闻ID标识符(如 /news/123) | 1. 动态路由配置(创建 news/[id]文件夹及page.js)<br>2. 提取URL参数:通过useParams()(客户端组件)或params参数(服务器组件)获取id并在页面输出 |
2. 公共组件开发任务
- 需求:创建独立的“主要标题组件”(Header),包含2个导航链接
- 功能点:
- 链接1:指向首页(
/) - 链接2:指向新闻列表页(
/news)
- 实现要点:
- 组件可放在
components文件夹(需手动创建),便于复用 - 使用
next/link组件确保客户端导航,避免页面刷新
三、关键注意事项
- 组件区分:服务器组件默认无需
'use client',仅当使用React hooks(如useState、useEffect)或浏览器API时,需声明为客户端组件
- 路由规则:App Router中,文件夹对应路由路径,
page.js为路由入口,动态路由需用[参数名]命名文件夹
- 开发与生产差异:开发环境缓存默认关闭,生产环境需手动配置缓存策略,避免旧数据展示
- 依赖版本:确保React版本与Next.js 15兼容(推荐React 19),避免因版本不匹配导致的语法错误
003 Exercise Solution - Part 1
一、核心知识点:路由配置与页面创建
1. 静态路由创建(以/news路径为例)
- 规则:Next.js App Router 采用“文件系统路由”,文件夹名称对应URL路径,需在文件夹内添加
page.js(或jsx/ts/tsx)作为页面入口。
- 步骤:
- 在
app目录下新建news文件夹(对应URL:/news); - 在
news文件夹中创建page.js,导出函数组件作为页面内容,示例代码:
- 验证:启动项目后,访问
http://localhost:3000/news,可看到“新闻页面”文本。
2. 动态路由创建(以/news/[id]路径为例)
- 场景:需实现URL参数动态变化(如新闻详情页
/news/first-news、/news/second-news)。
- 规则:动态路径段用“方括号包裹占位符”(如
[id]),占位符名称自定义(如[newsId]也可),同样需在动态文件夹内添加page.js。
- 步骤:
- 在
app/news目录下新建[id]文件夹(对应URL:/news/:id); - 在
[id]文件夹中创建page.js,示例代码:
- 验证:访问
http://localhost:3000/news/abc,可看到“新闻详细页面”文本,URL中abc即为动态参数id的值。
二、页面导航:Next.js 推荐方案
1. 避免使用原生<a>标签
- 问题:原生
<a>标签会导致页面全量刷新,破坏单页应用(SPA)的流畅性。
- 替代方案:使用 Next.js 内置的
Link组件,从next/link导入,确保导航在SPA流程内完成,无页面刷新。
2. Link组件使用示例(新闻列表页添加导航)
- 需求:在
/news页面添加3个链接,分别指向/news/first-news、/news/second-news、/news/third-news。
- 代码实现:
- 效果:点击链接时,URL更新但页面不刷新,直接渲染对应动态路由页面。
三、动态路由参数提取
1. 参数传递规则
- Next.js 会自动向动态路由的
page.js组件传递params属性(字幕中误称“parents”),该属性是对象类型,键为动态占位符(如id),值为URL中对应参数。
2. 提取id参数并展示
- 需求:在新闻详情页(
/news/[id])中显示当前URL的id值(如访问/news/second-news时,显示“新闻id:second-news”)。
- 代码实现:
- 效果:访问
/news/second-news时,页面显示“新闻id:second-news”,参数随URL动态变化。
004 Exercise Solution - Part 2
一、核心任务目标
向 Next.js 项目添加主要标题组件,组件需包含两个关键链接:
- 链接1:指向首页(路由路径为
/)
- 链接2:指向新闻页(路由路径为
/news)
- 组件定位:作为独立组件存在,需在所有页面内容上方显示,实现跨页面共享
二、项目结构与组件存放策略
1. 组件文件夹位置选择(灵活可选,无强制标准)
存放位置 | 具体路径示例 | 优势 |
应用内 | /app/components/ | 与应用核心代码关联紧密,适合小型项目 |
应用外(推荐) | /components/(与 /app 同级) | 结构清晰,便于大型项目组件复用与维护 |
- 结论:无最优方案,取决于个人/团队开发习惯,视频中采用“应用外同级文件夹”方案
2. 关键文件创建
- 组件文件:在
components/文件夹下新建导航栏组件文件(如MainHeader.js)
- 核心功能:导出
MainHeader组件函数,返回包含导航链接的 DOM 结构
三、导航组件实现步骤
1. 组件代码核心逻辑
2. 组件导入方式(利用 Next.js 路径别名)
- 路径别名规则:使用
@符号直接指向项目根目录,无需相对路径(如../)
- 导入代码示例:
- 优势:简化导入路径,避免多层嵌套导致的路径错误
四、布局(Layout)实现组件共享
1. 布局核心作用
- 解决问题:避免手动在每个页面组件中重复引入导航栏(低效且难维护)
- 核心价值:为所有页面创建“内容外壳”,实现共享组件(如导航、页脚)的统一管理
2. 根布局(Root Layout)操作
- 根布局位置:
/app/layout.js(Next.js 项目必有的核心文件,控制所有页面的公共结构)
- 引入导航组件步骤:
- 在
layout.js中导入MainHeader组件 - 在
body标签内,将{children}(页面动态内容)包裹在MainHeader下方 - 代码示例:
3. 效果验证
- 功能:保存后所有页面(包括首页、新闻页、详情页)顶部都会显示导航栏,点击链接可正常跳转
- 样式:初始无样式,后续可通过 CSS 模块、Tailwind 等方式优化
005 App Styling & Using Dummy Data - 应用样式优化与假数据使用
一、应用样式优化(核心操作)
1. 头部样式优化
- 文件替换:获取更新后的
main dash header.js文件,用其内容完全替换项目中原有同名文件,新文件通过新增标记和ID提升样式精细度,优化头部视觉效果(虽非最终完美版本,但为后续样式迭代打基础)。
- 效果目标:使应用头部布局更规整,为后续整体样式统一做铺垫。
2. 全局布局样式优化
- 关键操作:在
layout.js文件中,用带有id="page"的<div>标签包裹“主要标题+子内容”组合。
- 核心作用:通过该
div的样式配置(如添加padding),让页面内容与边缘保持合理间距,提升整体美观度,且优化效果同步适用于新闻页面。
3. 新闻页面链接样式优化
- 类名添加:打开新闻页面对应的JS文件,在存储链接的无序列表(
<ul>)内所有链接元素中,添加全局CSS已定义的新库存列表的道具类名。
- 效果逻辑:借助预配置的CSS规则,改善链接默认外观(如调整颜色、间距、 hover 效果等),使新闻项视觉区分度更高。
二、假数据应用(数据渲染流程)
1. 假数据准备
(1)假图片资源
- 存储路径:项目公共文件夹(
public)下的images/use子文件夹,内置用于项目演示的假图片,无需额外上传。
(2)假新闻数据文件
- 文件部署:将提供的
假新闻.js文件复制到项目根目录(与app、components文件夹同级)。
- 数据结构:文件导出含多个新闻项的数组,每个新闻项包含:
id:唯一标识(数字/字符串格式)slug:URL友好型标识(替代id生成易读URL,如“2024-nextjs-update”)标题图像:对应假图片文件名(关联public/images/新闻路径下的图片)日期:新闻发布时间(如“2024-12-01”)占位内容:新闻正文文本(用于填充页面)
2. 新闻页面数据渲染
(1)数据导入
- 在新闻页面JS文件顶部,通过
import 占位新闻 from './假新闻.js'(路径需根据实际项目结构调整)导入假新闻数组。
(2)动态生成JSX
- 映射数据:通过
占位新闻.map(新闻项 => { ... })遍历数组,为每个新闻项生成: - 带
新闻项.id的列表项(<li key={新闻项.id}>) - 可点击链接(
<a>):href用模板字符串动态构建,如/news/${新闻项.slug}(使用slug确保URL美观且SEO友好) - 新闻图片:
<img src={/images/新闻/${新闻项.标题图像}} alt={新闻项.标题}(路径匹配公共文件夹结构,alt文本提升可访问性) - 新闻标题:用
<span>标签展示新闻项.标题
3. 新闻详情页数据匹配与渲染
(1)识别当前新闻项
- 数据导入:同新闻页面,导入
假新闻.js文件。
- 匹配逻辑:通过URL中的
slug参数(如/news/2024-nextjs-update中的2024-nextjs-update),结合假新闻.find(项 => 项.slug === URL中的slug)找到当前需展示的新闻项。
(2)页面内容渲染
- 用
<article class="news-详情">标签包裹所有内容(类名用于样式控制),内部依次渲染: - 新闻图片:
<img src={/images/新闻/${新闻项.标题图像}} alt={新闻项.标题} - 新闻标题:
<h1>{新闻项.标题}</h1> - 发布时间:
<time datetime={新闻项.日期}>{新闻项.日期}</time>(datetime属性符合语义化标准) - 新闻正文:
<p>{新闻项.占位内容}</p>
006 Handling Not Found Errors & Showing Not Found Pages - 处理“未找到页面”(404错误)
一、核心目标
解决用户访问不存在页面/资源(如无效路由、不存在的新闻文章)时的错误提示问题,通过自定义未找到页面提升用户体验,避免直接暴露运行时错误。
二、关键实现方法
1. 创建全局未找到页面(捕获全站404错误)
- 文件要求:在项目
app文件夹根级别创建not-found.js文件(Next.js 15 App Router约定的特殊文件名,不可自定义)。
- 核心逻辑:文件内需导出一个组件函数,返回自定义错误提示内容(需保证样式适配项目),示例代码结构:
- 生效范围:捕获整个网站所有未找到错误(如访问
/abc、/invalid-page等无效路由)。
- 验证方式:保存文件后,在浏览器访问任意不存在的页面,即可看到上述自定义内容。
2. 创建路由特定未找到页面(适配子路由场景)
- 适用场景:针对特定子路由(如新闻详情页、商品详情页),需显示与该场景匹配的未找到提示(而非全局通用提示)。
- 实现步骤:
- 复制根级别
not-found.js文件,粘贴到目标子路由文件夹(如新闻相关的app/news文件夹); - 修改组件函数的文本内容,适配子路由场景,示例:
- 优先级规则:访问子路由下的无效路径(如
/news/abc)时,Next.js会优先加载子路由文件夹下的not-found.js,而非根级别文件。
3. 主动触发未找到错误(解决动态路由“假404”问题)
- 问题背景:动态路由页面(如新闻详情页
app/news/[slug].js)中,若根据URL的slug查询数据(如新闻文章)返回undefined(即数据不存在),Next.js不会自动触发404,而是会抛出运行时错误。
- 解决步骤:
- 导入触发函数:从
next/navigation中导入notFound函数(Next.js 15提供的官方工具函数); - 添加数据检查逻辑:在动态路由页面中,查询数据后判断是否存在,若不存在则调用
notFound()触发404,示例:
- 生效效果:访问
/news/abc(不存在的新闻slug)时,不再抛出运行时错误,而是显示app/news/not-found.js定义的内容。
三、关键注意事项
- 文件命名约束:未找到页面必须命名为
not-found.js,不可自定义(Next.js App Router的约定);
- 路由优先级:子路由下的
not-found.js优先级高于根级别,即“就近匹配”原则;
- 动态路由必做检查:动态路由页面(含
[param]的路由)必须添加数据存在性检查并调用notFound(),否则会出现运行时错误;
- 样式一致性:全局和路由特定的未找到页面需保持基础样式统一,避免用户体验割裂。
007 Setting Up & Using Parallel Routes
一、平行路由基础概念
- 定义:Next.js 的核心路由功能,支持在同一页面中同时渲染多个独立路由的内容(不同路径的页面可共存显示),适用于侧边栏、仪表盘分栏等场景(如案例中“新闻归档+最新新闻”双区域布局)。
- 核心价值:无需通过组件嵌套实现多区域展示,直接通过路由配置分离内容,提升代码可维护性。
二、平行路由配置步骤(关键操作)
1. 目录结构约定(必须遵循)
- 核心规则:平行路由文件夹需以
@符号开头(Next.js 识别标识),名称可自定义(需与布局组件中属性名对应)。
- 案例目录结构(以
/archive路径为例):
2. 编写平行路由页面(page.js)
- 每个
@xxx文件夹下的page.js对应一个平行区域的内容,与普通页面编写逻辑一致。
- 案例代码:
@archive/page.js(归档页面):@latest/page.js(最新新闻页面):
3. 配置布局文件(layout.js)—— 实现多路由同时显示
- 核心差异:普通布局仅通过
children属性渲染单个页面,平行路由布局需通过与平行路由同名的属性(如archive、latest)获取各区域内容。
- 案例代码:
- 访问效果:启动项目后访问
localhost:3000/archive,可同时看到“档案页”和“最新新闻页”的内容(默认上下排列,可通过 CSS 调整布局)。
三、后续扩展方向
- 功能增强:
- 将
@archive区域扩展为“按年份+月份筛选”的新闻归档列表,支持导航交互。 - 保持
@latest区域独立,始终显示最新新闻,不随归档筛选结果变化。
- 样式优化:通过 CSS(如 Flex/Grid)调整两个平行区域的布局(如左右分栏),提升页面美观度。
008 Working with Parallel Routes & Nested Routes - 并行路由与嵌套路由
一、核心需求与路由特性定位
- 并行路由的适用场景:单页显示多段内容可通过单页面实现,无需独立路由;但需实现“档案页按年份筛选新闻”这类需URL关联筛选条件、且页面多区块独立渲染的功能时,必须依赖并行路由。
- 嵌套路由的作用:在档案页(
/archive)下添加动态路由段(如[year]),将用户选择的年份作为URL占位符(如/archive/2024),实现“URL与筛选条件绑定”,便于定位和分享特定年份的新闻内容。
二、项目结构与辅助文件配置
1. 辅助文件(工具函数)设计
- 用途:封装假新闻数据处理逻辑,避免代码冗余,核心功能包括:
- 获取所有新闻包含的年份(按顺序排序);
- 筛选指定年份的新闻;
- 获取最新新闻列表。
- 存放路径:新建
lib文件夹(与components同级),创建news.js文件存储上述工具函数(非组件类代码,单独归类便于维护)。
2. 路由文件夹结构(关键)
三、核心功能实现步骤
1. 档案页年份导航(archive/page.js)
- 替换页面结构:用
<header>标签(用于样式化)替换原<h1>,内部添加<nav>+<ul>实现年份导航。
- 动态渲染年份链接:
- 导入
lib/news.js的“获取可用年份”函数,得到年份数组(如[2022,2023,2024]); - 通过
map遍历年份数组,生成<li>+<Link>(从next/link导入); - 链接路径动态拼接:
/archive/${year},文本显示年份,示例代码:
2. 新闻列表组件复用(components/list.js)
- 设计目的:主新闻页、档案筛选页均需显示新闻列表,封装为组件减少重复代码。
- 核心逻辑:
- 接收
newsprops(需筛选后的新闻数组); - 渲染
<ul>+<li>,每个列表项通过<Link>链接到新闻详情(需导入next/link,避免 reload 错误); - 示例代码:
3. 动态年份新闻筛选(archive/[year]/page.js)
- 获取年份参数:通过Next.js自动注入的
paramsprop获取动态路由值,即params.year([year]为路由占位符,故参数名是year)。
- 筛选并渲染新闻:
- 导入
lib/news.js的“筛选指定年份新闻”函数; - 调用函数传入
params.year,得到该年份新闻; - 引入
NewsList组件,传递筛选后的newsprops,示例代码:
4. 解决并行路由“未找到页面”错误
- 错误原因:并行路由(如
latest)与archive/[year]共享同一页面,latest路由默认不支持/archive/[year]这类嵌套路径,导致其中一个并行区块无匹配内容,触发404。
- 解决方案:添加
default.js文件: - 在
latest文件夹下创建default.js(文件名固定,Next.js识别为并行路由的 fallback 内容); - 内容与“最新新闻页”一致:调用
lib/news.js的“获取最新新闻”函数,渲染NewsList组件; - 效果:无论
archive路由下嵌套路径如何变化(如/archive/2024),latest区块始终显示最新新闻,不再触发404。
四、关键注意事项
- 组件导出要求:动态路由(如
[year]/page.js)必须默认导出React组件,否则点击年份会触发“非组件”错误。
- 开发服务器重启:修改路由结构(如添加
default.js)后,若出现错误需重启开发服务器,避免Next.js缓存旧路由配置。
- 并行路由核心逻辑:同一页面的多个并行路由(如
archive和latest)相互独立,需确保所有并行路由都支持当前URL路径(或通过default.js提供 fallback),否则会出现区块缺失。
五、最终效果与特性总结
- 功能验证:访问
/archive,页面上方显示年份导航,下方显示最新新闻;点击年份(如2024),URL变为/archive/2024,上方显示2024年新闻,下方最新新闻保持不变,实现“同一页面双路由独立渲染”。
- 特性定位:并行路由非高频刚需特性,但适用于“多区块独立控制、URL关联部分区块状态”的场景(如后台管理页的“列表+详情”、内容页的“筛选结果+推荐内容”),是Next.js路由系统的重要补充。
009 Configuring Catch-All Routes
一、核心问题:路由层级不足的痛点
在示例应用中,选择年份后出现以下问题,需通过通配符路由解决:
- 功能受限:仅能查看选中年份的文章,无法进一步选择“月份”筛选更细粒度的内容
- 导航消失:进入年份页面后,年份导航栏消失,用户无法返回或切换其他年份
- 路由刚性:标准动态路由(如
[year])仅能捕获单个路径分段,无法支持多层级(如“年份/月份”)的路径匹配
二、解决方案:通配符路由核心配置
1. 通配符路由的定义规则
- 语法格式:通过文件夹命名实现,将标准动态路由的
[标识符]改为[...标识符](方括号内添加“三个点+自定义标识符”)
- 示例:将原动态路由文件夹
[year]重命名为[...filter],其中“filter”为自定义标识符(可根据业务场景命名,如“params”“pathSegments”等)
2. 核心作用
- 捕获多段路径:可捕获目标路由(如
/archive)后的所有路径分段,无论分段数量(如/archive/2024“1段”、/archive/2024/03“2段”均能匹配)
- 路径数据格式:自定义标识符(如“filter”)会作为数组返回,数组元素为匹配的路径分段。例如:
- 访问
/archive:filter为undefined(无路径分段) - 访问
/archive/2024:filter为["2024"](1个分段) - 访问
/archive/2024/03:filter为["2024", "03"](2个分段)
三、实操步骤:从配置到验证
1. 路由文件改造
- 重命名动态路由文件夹:找到目标路由(如
/archive下的动态路由文件夹),将[year]改为[...filter]
- 调整页面组件代码:
- 重命名接收动态参数的常量:从
const { year } = params改为const { filter } = params - 添加测试日志:
console.log(filter),用于后续验证路径捕获结果 - 临时注释无效代码:若原代码依赖
year参数(如年份筛选逻辑),先注释以避免报错,返回占位内容(如<p>Loading filtered content...</p>)
2. 解决路由冲突
- 冲突原因:若
/archive目录下同时存在默认页面(如page.js)和通配符路由文件夹([...filter]),Next.js 会因“路由匹配歧义”报错
- 解决方案:
- 删除
/archive下的默认page.js(避免与通配符路由竞争匹配) - 将原默认页面的内容(如头部导航、文章列表组件)迁移到
[...filter]/page.js中,确保仅通配符路由页面加载
3. 测试与验证
- 重启开发服务器:保存修改后重启,确保无路由冲突报错
- 多场景验证:
- 访问
/archive:页面正常显示列表,终端日志输出filter: undefined - 访问
/archive/2024:终端日志输出filter: ["2024"],证明单段路径捕获成功 - 访问
/archive/2024/03:终端日志输出filter: ["2024", "03"],证明多段路径捕获成功
- 后续扩展:基于
filter数组数据开发筛选逻辑(如根据filter[0](年份)、filter[1](月份)过滤文章)
四、关键注意事项
- 路由优先级:通配符路由优先级低于具体路由(如
/archive/2024若存在单独的2024/page.js,会优先匹配该页面,而非通配符路由)
- 参数类型:
filter数组元素均为字符串类型,若需数字类型(如年份、月份),需手动转换(如const year = Number(filter[0]))
- 边界处理:需考虑
filter为undefined的场景(即访问根路由/archive),避免因“数组越界”导致报错
010 Catch-All Fallback Routes & Dealing With Multiple Path Segments - 路由与数据处理
一、Catch-All Fallback Routes 核心应用
1. 多路径段参数提取逻辑
- 参数获取与容错处理:通过筛选器(filter)提取路径中的年份、月份参数,用
filter?.[0](可选链+数组索引)简化判断,未定义时自动存储为undefined,避免代码报错 - 年份参数:
const selectedYear = filter?.[0] - 月份参数:
const selectedMonth = filter?.[1] - 替代方案(三元表达式):
const selectedYear = filter ? filter[0] : undefined(代码冗长,不推荐)
- 参数类型明确:已知
filter定义时为数组类型,可直接通过索引访问,无需额外类型断言
2. 动态路由路径配置
- 路径规则设计:基于“档案/年份/月份”层级结构,实现不同筛选维度的路由匹配
- 仅年份筛选:路径为
/档案/[年份](如/档案/2024) - 年份+月份筛选:路径为
/档案/[年份]/[月份](如/档案/2024/1)
- 动态链接生成:通过条件判断动态设置
Link组件的href属性
二、数据筛选与页面渲染
1. 新闻数据按需获取
- 数据获取函数调用:根据筛选参数调用对应工具函数,实现精准数据筛选
- 仅年份:
getNewsByYear(selectedYear)(需传入年份参数) - 年份+月份:
getNewsByYearAndMonth(selectedYear, selectedMonth)(需传入两个参数)
- 数据有效性校验:通过
if (news && news.length > 0)确保数据为非空数组,避免渲染空列表
2. 备用内容与条件渲染
- 默认备用内容:初始定义
content = <p>未找到所选时间段的内容</p>,作为无数据时的兜底显示
- JSX根元素约束:多个JSX元素需用
<>(片段)或容器标签包裹,避免语法错误
三、导航与路由状态管理
1. 导航显示逻辑控制
- 导航动态隐藏:当同时选中年份和月份(精确到月份筛选)时,将导航链接数组设为空
links = [],隐藏导航栏,避免冗余交互
- 导航状态恢复:返回上级页面(如从“年份+月份”回到“仅年份”)时,自动重新加载对应层级的导航选项(年份或月份)
2. 非支持路径处理
- 默认备用行为:当路径包含多余或不支持的段(如
/档案/2024/1/abc),因未匹配对应数据逻辑,会自动显示“未找到内容”的备用文本
- 自定义扩展方向:可通过添加路径校验逻辑(如判断路径段数量、格式),修改默认行为(如跳转404页面)
四、关键工具函数与依赖
工具函数 | 作用 | 所需参数 |
getNewsByYear | 获取指定年份新闻 | selectedYear |
getNewsByYearAndMonth | 获取指定年份+月份新闻 | selectedYear、selectedMonth |
getAvailableMonths | 获取指定年份下的可用月份列表 | selectedYear |
五、核心注意事项
- 参数容错:始终用可选链(
?.)处理路径参数,避免因参数缺失导致的运行时错误
- 数据校验:渲染列表前必须校验数据存在性和数组长度,提升用户体验
- JSX语法约束:严格遵守“单个根元素”规则,使用片段或容器标签包裹多元素
- 路由一致性:确保
Link的href路径与数据筛选逻辑匹配,避免“路径正确但数据不显示”的问题
011 Throwing (Route-related) Errors - 路由相关错误处理
一、核心问题背景
在基于Next.js 15的项目中,当用户在URL中输入无效路由内容(如过多路径段、不存在的年份/月份参数)时,默认仅显示回退文本,无法明确提示“错误”状态,需通过代码优化实现路由错误的精准捕获与反馈。
二、关键技术点与操作步骤
1. 错误触发条件设计(双重校验逻辑)
需在页面JS文件中,返回JSX内容前添加
if判断,满足任一条件即抛出错误,核心逻辑如下:校验类型 | 触发条件 | 实现方式 |
年份校验 | 存在“选定年份”,且该年份不在“可用新闻年份数组”中 | 使用数组 !includes()方法,否定“可用年份包含选定年份”的结果 |
月份校验 | 存在“选定月份”,且该月份不在“对应选定年份的可用新闻月份数组”中 | 通过逻辑或(` |
2. 类型不匹配问题解决方案
- 问题根源:年份/月份工具函数返回数字类型,但从URL路径提取的“选定年份/月份”为字符串类型,即使值相同,
includes()判断也会返回false(如4 === "4"为false)。
- 解决方法:在进行校验前,将从URL提取的“选定年份”和“选定月份”强制转换为数字类型(如
Number(selectedYear)),确保类型统一。
3. 开发模式与生产需求差异
- 开发模式表现:配置错误触发逻辑后,访问无效路由(如
/2025/13,13为无效月份)会显示Next.js默认的“开发模式错误覆盖层”,包含错误堆栈等技术信息。
- 生产需求:需替换默认错误覆盖层为自定义错误页面(如404页面、参数无效提示页),需额外添加错误处理逻辑(后续课程可能展开)。
三、核心代码逻辑(简化示例)
四、学习要点总结
- 路由错误处理需结合业务场景(如年份/月份筛选),明确“无效参数”的定义,避免误判;
- 处理URL参数时,必须注意类型一致性(字符串→数字转换是常见坑点);
- 开发模式的默认错误提示仅用于调试,生产环境需自定义友好的错误页面,提升用户体验;
- 错误触发逻辑需覆盖所有可能的无效场景(如本文中“年份+月份”双重校验),避免遗漏。
012 Handling Errors With Error Pages
一、核心目标
替换默认开发模式错误覆盖层,用自定义错误回退内容处理服务器端与客户端的错误,确保用户体验一致性。
二、关键实现方式:特殊错误文件(error.js)
- 文件特性:
- 功能类比
not-found.js(404页面),属于Next.js约定式特殊文件。 - 放置位置灵活:可在项目任意目录或特定页面同级目录,仅作用于当前目录及嵌套页面的错误处理。
- 触发逻辑:当对应页面或嵌套页面发生错误时,自动渲染
error.js中的组件。
- 基础代码结构:
三、核心规则:错误回退必须是客户端组件
- 强制要求:
- 必须在
error.js文件顶部添加'use client'声明,否则无法生效。
- 底层原因:
- 错误可能发生在两个阶段:
- 服务器端:页面初始渲染时(如数据请求失败);
- 客户端:页面加载后用户交互时(如动态操作触发异常)。
- 客户端组件可覆盖两端场景,因此是唯一适配方案。
组件类型 | 运行环境 | 错误处理适配性 |
客户端组件 | 服务器+客户端 | 支持两端错误捕获(推荐) |
未声明的服务器组件 | 仅服务器端 | 无法捕获客户端错误(不适用) |
四、关键Props:获取实际错误信息
- Next.js 会自动向
Error组件传递error对象(包含错误详情),可通过error.message输出具体错误原因,替代固定文本(如“无效路径”),便于调试和用户理解。
五、效果与后续操作
- 配置后效果:保存
error.js后,触发错误时会显示自定义错误页面,而非默认覆盖层。
- 用户体验保障:用户可通过页面交互(如返回按钮、导航链接)离开错误状态,继续使用应用。
013 Server vs Client Components
一、核心概念与本质差异
对比维度 | 服务器组件(Server Components) | 客户端组件(Client Components) |
执行位置 | 仅在服务器执行,组件函数不在客户端运行 | 服务器初始预渲染 + 客户端(浏览器)可执行 |
日志查看 | 控制台日志仅出现在开发服务器终端 | 日志可在浏览器开发者工具控制台查看 |
适用场景 | 无客户端交互需求的静态内容(如新闻列表、纯展示页面) | 需客户端交互/钩子的功能(如路由监听、表单交互) |
特殊规则 | next.js 中默认所有组件均为服务器组件 | error.js 定义的组件必须是客户端组件(需处理客户端代码错误) |
二、关键使用原则
- 默认优先用服务器组件
- 无需客户端交互时,不主动将组件转为客户端组件
- 优势:减少客户端代码加载量,降低浏览器负担,提升页面渲染效率
- 客户端组件的“必要场景”
- 需使用 React 钩子(如
usePathnameuseStateuseEffect)时 - 需处理客户端事件(如点击、输入、路由切换监听)时
- 需渲染动态交互内容(如高亮当前导航链接、表单提交)时
三、实践案例:导航链接高亮功能
1. 需求背景
给页面导航链接添加“当前路径高亮”效果,需判断当前 URL 路径是否匹配链接地址
2. 技术关键点
- 需使用
usePathname钩子(从next/navigation导入)获取当前路径
usePathname仅支持在客户端组件中使用,需手动添加use client指令
3. 优化方案:最小化客户端组件
- 问题:直接给整个头部组件(Header)加
use client会导致大量静态内容被标记为客户端组件,浪费资源
- 解决方案:拆分独立小型客户端组件
- 创建
NavLink.js组件,仅包含链接高亮逻辑 - 在
NavLink.js顶部添加use client指令,导入usePathname - 通过 props 接收
hrefchildren等参数,实现组件复用 - 主头部组件(Header)保持为服务器组件,引用
NavLink组件
4. 核心代码逻辑(简化版)
014 Nested Routes Inside Dynamic Route - 动态路由内嵌套路由
一、前置基础回顾
- 核心概念:服务器端组件与客户端组件是Next.js开发的重要基础,二者使用难度低,但需明确其差异与适用场景,为后续路由功能学习奠定基础。
- 学习衔接:掌握组件概念后,可深入探索Next.js路由特性,本次重点为“动态路由内的嵌套路由”,后续将进一步学习“拦截路由”。
二、动态路由内嵌套路由核心实现(以新闻图片全屏功能为例)
1. 需求场景
实现新闻详情页中图片的点击交互,点击后跳转至独立页面,以全屏形式展示该新闻对应的图片。
2. 文件结构配置
- 在动态路由文件夹(如
[slug],用于匹配新闻slug)内部,新建嵌套路由文件夹(名称自定义,示例为image)。
- 在
image文件夹中创建page.js文件,导出组件函数(命名为“ImagePage”),作为全屏图片展示页面的入口。
3. 组件逻辑实现(image/page.js)
(1)获取动态参数
- 通过组件接收的
props提取params属性(或parents属性,视路由层级而定),从中获取动态路由的slug参数(因嵌套路由会继承父级动态路由的参数)。
- 示例:
const { slug } = params;(类似动态路由页面直接获取slug的逻辑)。
(2)数据处理与异常控制
- 复制动态新闻详情页的逻辑,包括“新闻项查找”与“未找到页面”处理:
- 导入假新闻数据(如
fakeNews),根据slug匹配当前新闻项。 - 从
next/navigation导入NotFound组件,若未匹配到新闻项,返回<NotFound />,确保路由异常时的用户体验。
(3)动态渲染图片
- 构建图片容器:添加
full-screen-image类名的div作为全屏图片容器。
- 动态设置图片源:图片存储路径为
public/news/[图片名],其中图片名从匹配到的新闻项newsItem.image属性获取,示例:
4. 跳转链接配置(新闻详情页)
- 在动态新闻详情页(
[slug]/page.js)中,用next/link的Link组件包裹新闻图片,配置跳转路径: - 路径格式:
/news/${newsItem.slug}/image(对应“新闻根路由/动态slug/嵌套image路由”的文件结构)。 - 示例:
三、关键区分与后续方向
- 嵌套路由特性:动态路由内的嵌套路由是实用功能(开发中频繁用到),但本质是基于文件系统的路由层级扩展,并非“拦截路由”。
- 后续学习:本次仅完成嵌套路由实现,后续将探索“拦截路由”功能(一种特殊的路由拦截与展示机制)。
015 Intercepting Navigation & Using Interception Routes - 拦截路由(Interception Routes)
一、核心概念
- 定义:拦截路由是Next.js 15中一种根据导航方式动态切换页面内容的路由机制,针对相同URL路径,会依据用户“如何到达该路径”显示不同页面
- 核心逻辑:仅拦截“页面内部链接导航”(单页应用模式下的跳转),对“外部链接进入、手动输入URL、页面刷新”这三类场景不拦截,实现“同路径不同内容”的差异化展示
二、配置步骤(关键操作)
1. 文件夹命名规则(核心)
- 结构要求:创建与“目标拦截页面”同级的文件夹(非强制,但推荐,便于管理)
- 命名格式:
(路径标识)目标路径名,例如要拦截image路由: - 同文件夹拦截:命名为
(.)image(括号内的.代表当前文件夹,类似导入路径的./) - 嵌套路径上一层拦截:命名为
(..)image(括号内的..代表上一级文件夹,类似导入路径的../) - 多文件夹段:需按层级添加
..,具体可参考Next.js官方文档
- 注意:括号为普通圆括号,非方括号或其他符号
2. 页面文件创建
- 在配置好的拦截路由文件夹中,添加
page.js文件(Next.js App Router默认页面文件)
- 在该文件中定义“拦截状态下的页面内容”,示例:复制原
image页面代码,新增<h2>被拦截</h2>标识,用于区分拦截/非拦截状态
三、效果验证(核心差异)
导航方式 | 页面显示效果 | 加载文件 |
页面内部链接跳转(如从新闻页点击图片) | 显示拦截页面(含“被拦截”标识) | 拦截路由文件夹下的 page.js |
外部链接进入、手动输入URL、页面刷新 | 显示原页面(无“被拦截”标识) | 原 image路由下的page.js |
四、应用场景(重点用法)
- 单独使用:实现基础的“导航方式差异化展示”,如内部跳转显示简化版页面,外部进入显示完整页面
- 与并行路由(Parallel Routes)结合(推荐核心场景):
- 内部导航拦截时:在模态框(Modal)中显示内容,提升用户体验
- 外部进入/刷新时:以全屏页面显示内容,保证页面完整性
016 Combining Parallel & Intercepting Routes - 并行路由与拦截路由结合使用
一、核心目标
在Next.js 15中,通过结合并行路由(Parallel Routes) 与拦截路由(Intercepting Routes) ,实现“模态框覆盖层”功能——点击页面元素时以模态框形式展示内容,且背景保留原页面内容,而非跳转至全新全屏页面。
二、关键步骤与技术点
1. 基础:为拦截路由添加模态框结构
- 核心操作:在拦截路由对应的JS文件中,构建模态框基础DOM结构
- 创建
div并添加类名modal backdrop,作为模态框背景层 - 将模态框核心内容包裹在“对话容器”中,添加
模态类名与open属性(控制显示状态)
- 初始效果:
- 直接刷新页面:模态框页面仍为全屏显示
- 点击触发进入:页面以模态框形式展示,但背景无内容(因模态框页面仍占据全部布局空间)
2. 关键:用并行路由实现“覆盖层”效果
(1)并行路由配置逻辑
- 目标:让“原页面内容”与“模态框内容”在同一页面并行渲染,实现覆盖层效果
- 文件结构设计:
- 在父路由目录下,创建两个并行路由文件夹(兄弟关系):
模态:存放拦截路由对应的模态框组件默认/详细信息:存放原页面(如新闻详情页)组件(可选,也可通过默认children属性替代)- 父布局JS文件(位于并行路由文件夹上层):
- 接收
childrenprop:渲染原页面内容(如新闻详情) - 接收
modalprop(因并行路由标识符设为“模态”):渲染模态框内容 - 渲染顺序:将
modal内容输出在children上方,实现模态框覆盖原页面
(2)路径规则特殊说明
- 并行路由文件夹(如
模态、归档)不会影响URL路径,Next.js仅将其作为“组织文件的特殊目录”,忽略其在URL中的映射
- 拦截路由的路径描述(如
/(...拦截路由名))无需修改,即使移动到并行路由子文件夹中,仍保持原路径逻辑
3. 避坑:解决“无内容时的报错”
问题场景
当进入原页面(如
/news/[slug]新闻详情页),未触发拦截路由时,模态并行路由无内容可渲染,Next.js会因“该路径无组件”报错。解决方案
在
模态并行路由文件夹中,添加默认组件文件(如default.js):- 导出一个简单组件,直接返回
null
- 作用:明确告知Next.js“该并行路由此时无需渲染内容”,避免报错
三、最终效果与应用场景
1. 实现效果
- 触发拦截路由(如点击新闻详情页中的图片):模态框以覆盖层形式打开,背景保留原新闻详情页内容
- 未触发拦截路由:仅显示原页面内容,
模态并行路由因默认组件返回null而不渲染
2. 应用场景
适用于需要“在当前页面之上临时展示内容”的场景,如:
- 图片预览模态框
- 临时表单弹窗
- 详情快速查看窗口
017 Replace page.js with default.js
You might be getting an error when trying to refresh the image detail route (
/news/<some-news-identifier>/image).尝试刷新图片详情路由(/news/<some-news-identifier>/image)时,你可能会遇到错误。In that case, rename
news/[slug]/@modal/page.js to default.js.在这种情况下,请将news/[slug]/@modal/page.js重命名为default.js。
@modal 文件夹中创建default.js 文件:
这个问题的根本原因是 Next.js 并行路由的工作方式:
- 当你从新闻详情页点击图片链接时,拦截路由
@modal/(.)image会被触发,在模态框中显示图片,而不会导航到新页面。
- 但是当你直接访问或刷新
/news/[slug]/imageURL 时,Next.js 需要渲染所有插槽,包括@modal插槽。
- 由于没有为
@modal插槽定义默认组件(default.js),Next.js 不知道该渲染什么,因此回退到最近的 NotFound 边界,导致 404 错误。
通过创建一个返回
null 的 default.js 文件,我们告诉 Next.js 在没有特定模态内容时不要渲染任何东西,这样就能避免 404 错误,让页面正常显示图片内容。018 Navigating Programmatically - 程序化导航
一、核心功能需求与实现目标
- 需求场景:点击模态框背景幕布,返回之前访问的页面(如从列表页进入的详情页)
- 导航触发方式:通过代码逻辑触发页面导航,而非用户点击链接或浏览器返回按钮
二、关键技术与实现步骤
1. 路由钩子导入与使用
- 导入路径:必须从
next/navigation导入路由钩子(不可使用其他包)
- 核心对象:通过钩子获取
router对象,包含多种程序化导航方法 push():将新页面推入路由堆栈(新增历史记录)refresh():手动刷新当前页面back():返回上一页(核心需求对应方法,点击背景幕布时触发)
2. 事件绑定注意事项
- 正确绑定方式:在
onClick中直接指向router.back(无需加括号()),避免立即执行
3. 客户端组件限制
- 使用范围:路由钩子仅支持在客户端组件中使用
- 启用方式:需在文件顶部添加
'use client'指令声明客户端组件
三、功能验证与效果
- 操作流程:刷新页面进入详情页 → 点击模态窗口打开 → 点击背景幕布
- 预期结果:模态窗口关闭,页面导航回上一页面,地址栏路径同步更新
- 异步客户端组件 :在 Next.js 中,客户端组件(使用 'use client' 指令)不能是异步函数。只有服务端组件可以是异步的。
- 解决方案 :
- 移除了 async 关键字
- 使用 useEffect 钩子来处理异步操作
- 添加了 useState 来管理新闻项数据和加载状态
- 在 useEffect 中处理异步参数解析和数据获取
- 改进点 :
- 添加了加载状态显示
- 增加了错误处理
- 保持了原有的功能不变
客户端组件不能是异步的主要原因是 React 的渲染模型和设计哲学:
1. React 渲染机制
React 组件的渲染必须是同步且可预测的。React 需要能够:
- 立即计算出组件的 UI 输出
- 跟踪状态变化和依赖关系
- 在状态变化时重新渲染组件
异步组件会破坏这种同步渲染模型,因为 React 无法知道异步操作何时完成。
2. 客户端 vs 服务端组件的区别
服务端组件(Server Components):
- 在服务器上运行
- 可以是异步的,因为它们直接访问数据源
- 渲染完成后发送 HTML 到客户端
- 不参与客户端的交互式渲染
客户端组件(Client Components):
- 在浏览器中运行
- 必须是同步的,因为它们参与 React 的交互式渲染循环
- 使用 hooks(如
useState,useEffect)处理状态和副作用
3. Next.js 的设计决策
Next.js 15 中的这个限制是为了:
- 保持 React 组件的渲染可预测性
- 防止渲染过程中的不确定性
- 确保组件生命周期的一致性
4. 正确的处理方式
在客户端组件中处理异步操作的标准方法是:
这种模式将异步操作从组件渲染过程中分离出来,放入副作用钩子中,保持了组件渲染的同步性。
019 Defining the Base HTML Document
Currently, this project has a small bug / issue - the root HTML document is re-defined for every route. The fix is to define the base HTML document only once in a
layout.js file inside the root folder path.目前,该项目存在一个小bug/问题——每个路由都会重新定义根HTML文档。解决方法是在根文件夹路径下的layout.js文件中仅定义一次基础HTML文档。Create an
app/layout.js file with the following content:创建一个app/layout.js文件,内容如下:When following along with the next lecture, you'll also need to tweak the
app/(content)/layout.js and app/(marketing)/layout.js files (which are created in the next lecture).在学习下一节课时,你还需要调整app/(content)/layout.js和app/(marketing)/layout.js文件(这些文件将在下一节课中创建)。app/(content)/layout.js(created in next lecture, adjust it after watching the next lecture)(将在下一讲中创建,观看下一讲后进行调整)
app/(marketing)/layout.js(created in next lecture, adjust it after watching the next lecture)(将在下一讲中创建,观看下一讲后进行调整)
020 Using & Understanding Route Groups - 路由组(Route Groups)
一、核心需求背景
在Next.js应用开发中,默认根布局会作用于所有页面(如统一导航栏),但实际场景中存在差异化布局需求:网站起始页(着陆页)常需与其他功能页面(如新闻、归档)使用不同布局(例:起始页无导航,功能页显示导航),路由组(Route Groups)是解决该问题的关键特性。
二、路由组核心概念
- 定义:Next.js App Router中的布局隔离工具,通过特定文件夹命名规则,为一组路由配置独立布局,且不影响URL路径。
- 关键特征:
- 文件夹命名格式:用
()包裹自定义名称(例:(content)、(marketing)),括号内名称仅作标识,不参与URL生成。 - 作用范围:可在app文件夹顶级目录或嵌套路由中创建,组内路由共享该组专属布局。
- 与普通路由文件夹区别:普通文件夹(如
news)会生成URL路径(例:/news),路由组文件夹不添加任何URL片段。
三、实操步骤(以“起始页与功能页分布局”为例)
1. 创建路由组文件夹
在
app文件夹下新建两个路由组文件夹:(content):存放应用核心功能路由(如news、archive),对应“带导航”的布局。
(marketing):存放营销/着陆页路由(如起始页page.js),对应“无导航”的布局。
2. 迁移路由与配置布局
操作对象 | 具体步骤 |
功能路由( news、archive) | 1. 将原有 news、archive文件夹及嵌套路由,移动到(content)文件夹内;<br>2. 将原根布局文件(layout.js)复制到(content)文件夹,保留导航相关代码(如<MainNav>),并调整全局CSS导入路径(因在子文件夹,需改为../globals.css)。 |
起始页路由( page.js) | 1. 将原起始页 page.js移动到(marketing)文件夹内;<br>2. 复制(content)/layout.js到(marketing)文件夹,删除导航相关代码(如<MainNav>、导航样式div),同样调整全局CSS导入路径。 |
3. 处理特殊页面(404未找到页)
- 规则:设置路由组后,所有页面(包括
not-found.js)必须归入某一路由组,不可在app根目录单独存在。
- 操作:将
not-found.js移动到(content)文件夹,确保功能页场景下的404页面使用“带导航”布局。
4. 验证效果
- 访问起始页(URL:
/):加载(marketing)/layout.js,无导航,符合预期。
- 访问新闻页(URL:
/news):加载(content)/layout.js,显示导航,符合预期。
四、核心价值与应用场景
- 核心价值:实现“路由分组-布局绑定”,避免布局代码冗余,同时保持URL简洁。
- 典型应用场景:
- 多模块隔离:如“用户中心模块”(
(user))与“公共模块”((public))分属不同路由组,使用不同布局。 - 营销页与功能页分离:如活动着陆页(无导航)与产品功能页(有导航)的布局隔离。
- 权限相关布局:如“登录页组”(
(auth),无侧边栏)与“登录后页组”((dashboard),有侧边栏)的区分。
五、注意事项
- 布局文件路径:路由组内的
layout.js仅对组内路由生效,若需全局共享基础样式(如重置样式),可在app/layout.js中保留公共样式导入,路由组布局通过childrenprop嵌套使用。
- CSS导入路径:路由组文件夹为子目录,需根据相对路径调整CSS导入(例:
(content)/layout.js导入根目录globals.css时,路径为../globals.css)。
- 页面归属:
app根目录下不可保留除路由组、globals.css、favicon.ico外的其他页面文件(如单独的page.js、not-found.js),必须归入路由组。
021 Building APIs with Route Handlers - 路由处理程序
一、核心定义与定位
- 本质:Next.js 中用于构建 API 类路由的特性,不渲染页面、无需布局,仅处理数据交互(非页面渲染场景)
- 核心作用:实现后台数据操作,包括产生数据、存储数据、接收/返回请求等,支持与外部客户端(如移动应用、前端页面)通信
- 与普通页面路由区别:不属于路由组,无需布局文件,不生成可视化页面,仅响应数据请求
二、文件创建与命名规则
配置项 | 具体要求 | 示例 |
路径位置 | 需放在路由组之外(避免继承不必要的布局) | 项目根目录下创建 api 文件夹(路径名称可自定义) |
核心文件 | 必须命名为 route.js(Next.js 非保留名,专门用于路由处理程序) | api/route.js |
导出函数 | 函数名需与 HTTP 方法一致,支持 get、post、patch、put、delete 等 | 导出 async function GET() {} 处理 GET 请求 |
三、请求与响应处理
- 请求对象(Request)
- 由 Next.js 自动传递,包含请求方法、请求体、请求头、查询参数等信息
- 可提取关键数据:如从请求体中获取客户端提交的数据,用于数据库存储;从请求方法中判断请求类型
- 调试方式:在处理函数中打印请求对象,可在服务器端终端查看详细数据
- 响应对象(Response)
- 需手动构建并返回,基于浏览器和 Node.js 内置的
Response类 - 支持响应类型:纯文本、JSON 数据(可使用
Response.json()工具方法简化 JSON 响应) - 示例代码:
四、关键特性
- 多请求类型支持:同一
route.js文件中可导出多个不同 HTTP 方法的函数,处理同一路径的不同请求(如 GET 查数据、POST 存数据)
- 请求触发方式:GET 请求可直接通过浏览器输入路径触发(如
http://localhost:3000/api);其他类型请求需通过前端代码(如 fetch、axios)或外部客户端发送
- 无布局依赖:因不渲染页面,无需继承路由组的布局,独立于页面渲染流程
五、应用场景与学习意义
- 核心应用场景
- 为 Next.js 应用对接外部客户端(如移动 App),提供数据接口
- 处理前端页面的后台数据交互(如表单提交、数据查询,不用于页面整体渲染)
- 实现数据存储、第三方 API 转发等服务器端操作
- 学习必要性
- 虽非所有 Next.js 项目必需,但是构建全栈应用的重要能力
- 拓展 Next.js 应用的适用范围,从单纯页面渲染延伸到数据服务提供
六、使用注意事项
- 若不需要处理某类 HTTP 请求(如 POST),可注释或删除对应导出函数,避免不必要的请求处理
- 提取请求体数据时需注意数据验证,防止非法数据提交
- 部署时需确保路由路径配置正确,避免与其他页面路由冲突
Next.js 15 路由处理程序 vs 传统后端API:核心区别解析
Next.js 15 的路由处理程序(Route Handlers)本质是前端框架内置的服务端数据交互层,与 Node.js/Java/PHP 等构建的传统后端API存在底层设计、部署形态、使用场景等多维度差异,以下是核心区别梳理:
对比维度 | Next.js 15 路由处理程序 | 传统后端API(如Express/Koa/Java Spring/PHP) |
核心定位 | 前端框架的“内置服务端能力”,为Next.js应用提供数据接口,属于全栈框架的一部分,服务于前端页面/客户端的数据需求 | 独立的“后端服务”,专注处理全系统的业务逻辑、数据存储、权限控制,是前后端分离架构的核心后端层 |
技术栈依赖 | 强绑定Next.js/React生态,仅支持JavaScript/TypeScript,复用前端项目的依赖、配置(如环境变量、TS配置) | 技术栈独立:可选择Node.js(Express)、Java、Python、PHP等,与前端技术栈解耦,可单独选型 |
部署形态 | 与Next.js前端应用同部署(如Vercel、Netlify、服务器部署Next.js项目),无需单独部署后端服务;支持边缘运行时(Edge Runtime),可部署在CDN边缘节点 | 需独立部署(如部署到服务器、容器、云函数),与前端应用分离,通常通过域名/端口独立访问(如 api.xxx.com) |
路由规则 | 基于文件系统路由: route.js文件的存放路径即API路径(如app/api/user/route.js对应/api/user),无需手动配置路由映射 | 需手动配置路由规则(如Express的 app.get('/api/user', handler)、Spring的@RequestMapping),路由与文件路径无强关联 |
运行环境 | 支持两种运行时:<br>1. 节点运行时(Node.js Runtime):基于Node.js,可使用Node.js API;<br>2. 边缘运行时(Edge Runtime):轻量、跨平台,无Node.js内置模块(如 fs),适合高频轻量请求 | 依赖特定运行环境:<br>- Node.js系(Express/Koa):需Node.js运行时;<br>- Java系:需JVM;<br>- PHP:需PHP解释器+Nginx/Apache |
与前端的耦合度 | 高度耦合:<br>1. 可直接复用前端的类型定义(TS)、工具函数;<br>2. 可直接访问Next.js的内置能力(如React Server Components、缓存、中间件);<br>3. 路径与前端路由统一管理,避免跨域(同域) | 低耦合:<br>1. 与前端完全分离,仅通过HTTP接口通信;<br>2. 需单独处理跨域(CORS)、接口鉴权、数据格式协商;<br>3. 前端需通过 fetch/axios跨域请求,需处理请求头、状态码等 |
业务能力边界 | 适合轻量级数据交互:<br>- 前端页面的表单提交、数据查询;<br>- 第三方API转发、简单数据处理;<br>- 与Next.js缓存(如SWR/React Cache)联动;<br>不适合复杂业务:如分布式事务、高并发数据库操作、复杂权限体系 | 适合全量后端业务:<br>- 复杂业务逻辑(如订单处理、支付流程);<br>- 分布式系统、微服务架构;<br>- 高并发、高可用设计(如负载均衡、数据库集群);<br>- 底层数据存储、权限中心、日志系统等 |
开发与调试效率 | 一站式开发:<br>- 前端开发者无需切换技术栈,用JS/TS即可开发;<br>- 与Next.js前端代码同仓库,调试时无需跨项目;<br>- 热更新、断点调试与前端统一 | 跨栈开发:<br>- 需独立的后端开发团队、技术栈;<br>- 前后端分仓库,调试需联调(如接口文档、环境配置);<br>- 后端修改需单独重启服务,调试成本高 |
性能与优化 | 内置优化能力:<br>- 边缘运行时可就近响应请求(CDN边缘节点),降低延迟;<br>- 复用Next.js的缓存策略(如Data Cache、Full Route Cache);<br>- 支持流式响应(Streaming Response),适配React的流式渲染 | 需手动优化:<br>- 需自行配置缓存(如Redis)、负载均衡、CDN;<br>- 流式响应、压缩等需手动实现;<br>- 性能优化依赖后端开发者的经验(如数据库索引、接口缓存) |
扩展性 | 扩展性有限:<br>- 仅能基于Next.js生态扩展,无法对接非JS生态的中间件/插件;<br>- 不支持微服务拆分,适合单体全栈应用 | 扩展性强:<br>- 可根据业务拆分微服务、接入各类中间件(如消息队列、分布式缓存);<br>- 支持多语言、多框架对接,适配复杂业务场景 |
核心差异总结
- 设计初衷不同:
- Next.js 路由处理程序:为了让前端开发者“无感知”地实现服务端数据交互,降低全栈开发门槛,核心服务于Next.js应用本身,是“前端框架的延伸”;
- 传统后端API:为了构建独立的、通用的后端服务,支撑全系统的业务逻辑,可对接多个前端(Web/APP/小程序),是“独立的服务层”。
- 适用场景不同:
- 选路由处理程序:Next.js 单体全栈应用、轻量级数据接口(如表单提交、简单查询)、需要与React Server Components联动、追求开发效率;
- 选传统后端API:复杂业务逻辑(如支付、订单)、多前端对接、高并发/高可用要求、需要微服务架构、非JS技术栈选型。
- 开发体验不同:
- 路由处理程序:前端开发者“一站式搞定”,无需跨栈,同仓库、同语言、同调试环境;
- 传统后端API:前后端分离,需联调、定义接口文档、处理跨域/鉴权,适合专业后端团队维护。
补充:两者的融合使用
实际项目中并非非此即彼:可基于Next.js路由处理程序做轻量接口层(如前端数据适配、缓存、第三方API转发),再对接传统后端API处理复杂业务(如数据库操作、权限校验),兼顾开发效率与业务复杂度。
多个 route.js 文件
Next.js 15 路由处理程序的核心设计就是基于文件系统的路由规则,多个
route.js 对应不同的 API 路径,是构建多接口的核心方式,以下是详细说明:一、多个 route.js 的存在形式:按路径分层
每个
route.js 独立对应一个 API 路径,文件的存放路径决定了接口的访问地址,示例如下:文件路径 | 对应的 API 访问路径 | 功能说明 |
app/api/user/route.js | http://localhost:3000/api/user | 处理用户相关请求(如查用户、创建用户) |
app/api/post/route.js | http://localhost:3000/api/post | 处理文章相关请求(如查文章、发布文章) |
app/api/order/route.js | http://localhost:3000/api/order | 处理订单相关请求(如创建订单、查订单) |
二、关键规则:确保多个 route.js 不冲突
- 同一目录下只能有一个 route.js:
单个文件夹内不能存在多个
route.js(如app/api/user/下只能有一个route.js),否则 Next.js 会报错;但该文件内可导出多个 HTTP 方法函数(GET/POST/PUT 等),处理同一路径的不同请求类型。
- 支持嵌套路径创建多 route.js: 可通过嵌套文件夹实现更细粒度的接口拆分,例如:
app/api/user/detail/route.js→/api/user/detail(查用户详情)app/api/user/edit/route.js→/api/user/edit(编辑用户信息)
- 独立处理逻辑:
每个
route.js是独立的模块,可编写专属的业务逻辑,互不干扰;也可复用公共工具函数(如数据库连接、数据验证)。
三、多 route.js 的优势
- 接口模块化:按业务模块(用户、文章、订单)拆分
route.js,代码结构清晰,便于维护;
- 职责单一:每个
route.js专注处理一类业务的接口,符合“单一职责原则”;
- 独立调试:可单独测试某一个
route.js对应的接口,无需影响其他接口;
- 灵活扩展:新增业务接口时,只需新增对应文件夹和
route.js,无需修改现有代码。
四、示例:多 route.js 的实际配置
app/api/user/route.js 示例代码:app/api/post/route.js 示例代码:五、注意事项
- 避免路径冗余:不要创建无意义的嵌套路径(如
api/user/user/route.js),保持路径简洁;
- 公共逻辑抽离:多个
route.js若需复用相同逻辑(如鉴权、数据库连接),可抽离为公共函数/中间件,避免重复代码;
- 路由冲突:确保
route.js的路径不与前端页面路由(如app/user/page.js)冲突,Next.js 会优先匹配route.js对应的 API 路由。
综上,多个
route.js 是 Next.js 15 构建多接口的标准方式,核心是通过“文件路径对应 API 路径”的规则,实现接口的模块化管理。022 Using Middleware - 中间件
注意:
middleware文件约定已被弃用,并已重命名为proxy。有关更多详细信息,请参阅迁移至代理。
https://nextjs.org/docs/app/api-reference/file-conventions/proxy
一、基础设置:文件位置与命名规则
- 文件路径:不依赖
app文件夹,需放在项目根目录(与package.json同级)
- 文件名:固定为
middleware.js(保留文件名,不可自定义)
- 核心导出:必须导出名为
middleware的函数(函数名固定,Next.js自动识别)
二、函数结构与依赖导入
- 函数参数与返回值
- 自动接收
request请求对象(与路由处理程序一致) - 必须返回
NextResponse(需从next/server导入,不可省略)
- NextResponse 核心功能
- 基础能力:从零创建新响应、转发请求(通过
next()方法,将请求导向原始目的地) - 实用场景:实现重定向(如未认证用户跳转登录页)、修改请求头/参数等
三、核心作用与运行机制
- 核心定位:非“请求处理者”,而是“请求拦截器”
- 主要用途:查看请求内容、修改请求参数、阻止非法请求、实现路由级认证
- 特殊能力:可拦截网站所有请求(包括页面请求、图片/图标等资源请求)
- 运行特性:每次请求触发(无论访问哪个页面/路由),重启开发服务器后生效
四、请求过滤:matcher 配置
- 配置方式:导出
config对象(变量/常量均可,需为对象类型),设置matcher属性
- 功能作用:指定哪些请求会触发中间件,过滤无关请求(如仅拦截特定页面请求,排除图片请求)
- 高级用法:支持数组格式与占位符,匹配多路由(如
['/news/:id', '/profile']),具体规则参考Next.js官方文档
五、实际验证与注意事项
- 服务器日志验证:重启开发服务器后加载页面,日志会显示中间件为每个请求运行(如访问新闻页时,日志包含页面请求、页面内图片请求)
- 课程定位:当前项目暂无需使用中间件,但属于Next.js路由体系核心功能,需掌握其原理以应对复杂场景(如全局认证、请求过滤)
📎 参考文章
- 一些引用
- 引用文章
欢迎您在底部评论区留言,一起交流~
Loading...
