Next.js路由系统全面指南:从基础到高级的最新实现
Next.js作为React生态系统中最受欢迎的框架之一,其路由系统经历了从传统客户端路由到服务端路由的演进,最终形成了当前基于文件系统的两种路由系统:应用路由(App Router)和页面路由(Pages Router)。这两种路由系统各有特点,适用于不同场景,共同构成了Next.js强大的路由能力。本文将详细介绍Next.js最新路由系统的实现方式,从最基础的静态路由到复杂的动态路由、API路由和权限控制,每种情况都提供文件路径结构说明和代码示例,帮助开发者全面掌握Next.js路由的使用方法。
一、应用路由与页面路由系统概览
Next.js目前支持两种路由系统:应用路由(App Router)和页面路由(Pages Router)。这两种路由系统在设计理念、实现方式和适用场景上存在显著差异。
应用路由是Next.js 13版本引入的新路由系统,基于React 18的组件架构和服务器组件(Server Components)技术。它采用更直观的文件系统路由方式,通过目录层级自动映射路由路径,支持更灵活的布局管理和更高效的渲染策略。应用路由特别适合新项目开发,因为它能够充分利用React的新特性,提供更好的性能和更简洁的代码结构。
页面路由是Next.js的传统路由系统,基于React 17及之前的版本,通过在pages目录中创建文件来定义路由。它仍然被广泛使用,特别是对于已有项目维护。页面路由系统兼容性更好,适合需要与旧版React或第三方库集成的场景。
| 特性 | 应用路由 (App Router) | 页面路由 (Pages Router) |
|---|---|---|
| 文件位置 | app/目录 |
pages/目录 |
| 核心组件 | page.tsx |
普通React组件 |
| 布局组件 | layout.tsx |
_app.js和_document.js |
| 动态路由 | [param]和[...param] |
[param]和[...param] |
| 数据获取 | 直接在组件中使用fetch |
通过getServerSideProps或getStaticProps |
| 路由导航 | useParams和useRouter |
useRouter |
| 中间件支持 | 原生支持 | 需要额外配置或第三方库 |
二、静态路由:最基础的路由实现
静态路由是最简单的路由类型,直接对应固定URL路径。在两种路由系统中,实现方式有所不同。
应用路由中的静态路由
在应用路由系统中,静态路由通过在app/目录下创建包含page.tsx文件的目录来实现。文件名直接映射为路由路径。
文件路径结构:
app/
page.tsx // 对应根路径 /
about/
page.tsx // 对应 /about
blog/
page.tsx // 对应 /blog
组件示例:
tsx
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>关于我们</h1>
<p>这是我们的公司介绍页面。</p>
</div>
);
}
页面路由中的静态路由
在页面路由系统中,静态路由通过在pages/目录下创建普通JSX文件实现,文件名直接映射为路由路径。
文件路径结构:
pages/
index.js // 对应根路径 /
about.js // 对应 /about
blog.js // 对应 /blog
组件示例:
jsx
// pages/about.js
export default function About() {
return (
<div>
<h1>关于我们</h1>
<p>这是我们的公司介绍页面。</p>
</div>
);
}
特殊静态路由
两种路由系统都支持一些特殊静态路由,如根路径、404页面等。
应用路由的特殊静态路由:
tsx
// app/page.tsx - 根路径 /
export default function Home() {
return <h1>欢迎来到首页</h1>;
}
// app/notfound.tsx - 404页面
export default functionNotFound() {
return (
<div>
<h1>页面未找到</h1>
<p>您请求的页面不存在。</p>
</div>
);
}
页面路由的特殊静态路由:
jsx
// pages/index.js - 根路径 /
export default function Home() {
return <h1>欢迎来到首页</h1>;
}
// pages/404.js - 404页面
export default functionNotFound() {
return (
<div>
<h1>页面未找到</h1>
<p>您请求的页面不存在。</p>
</div>
);
}
三、动态路由:基于参数的路由匹配
动态路由允许创建基于参数的路由,根据URL中的参数渲染不同的内容。Next.js支持两种动态路由类型:命名参数路由和catch-all路由。
命名参数路由
命名参数路由使用方括号[param]定义,匹配固定数量的路径段。
应用路由中的命名参数路由
文件路径结构:
app/
users/
[id]/ // 动态参数 id
page.tsx // 对应 /users/123
组件示例:
tsx
// app/users/[id]/page.tsx
import {路由器} from 'next/navigation';
export default async function UserPage({ params }) {
const { id } = await params; // Next.js 15+需用await解构
const response = await fetch(`https://api.example.com/users/${id}`);
const user = await response.json();
// 参数验证
if (!user) {
return <div>用户不存在</div>;
}
return (
<div>
<h1>{user.name}</h1>
<p>邮箱:{user.email}</p>
<p>角色:{user.role}</p>
</div>
);
}
页面路由中的命名参数路由
文件路径结构:
pages/
users/
[id].js // 动态参数 id
index.js // 对应 /users
组件示例:
jsx
// pages/users/[id].js
import {路由器} from 'next/router';
export default function UserPage() {
const router =路由器();
const { id } = router.query; // 通过query对象获取参数
return (
<div>
<h1>用户ID: {id}</h1>
<p>这是用户详情页面。</p>
</div>
);
}
// 服务端数据获取
export async function getServerSideProps(context) {
const { id } = context.params; // 通过context.params获取参数
const response = await fetch(`https://api.example.com/users/${id}`);
const user = await response.json();
// 参数验证
if (!user) {
return { notFound: true }; // 返回404页面
}
return {
props: { user }, // 将数据传递给页面组件
};
}
Catch-all路由
Catch-all路由使用[...param]语法定义,可以匹配任意数量的路径段。
应用路由中的Catch-all路由
文件路径结构:
app/
docs/
[...slug]/ // 动态参数 slug
page.tsx // 对应 /docs/任意路径段
组件示例:
tsx
// app/docs/[...slug]/page.tsx
export default function DocsPage({ params }) {
const { slug } = params; // slug是一个数组
// 模拟从API获取文档数据
const docData = await fetchDocData slug.join ( '/' );
return (
<div>
<h1>文档路径:{slug.join('/')}</h1>
<p>{docData.content}</p>
</div>
);
}
页面路由中的Catch-all路由
文件路径结构:
pages/
docs/
[...slug].js // 动态参数 slug
组件示例:
jsx
// pages/docs/[...slug].js
import {路由器} from 'next/router';
export default function DocsPage() {
const router =路由器();
const { slug } = router.query; // slug是一个数组
return (
<div>
<h1>文档路径:{slug.join('/')}</h1>
<p>这是文档内容页面。</p>
</div>
);
}
可选Catch-all路由
可选Catch-all路由使用双方括号[[...param]]语法定义,允许匹配根路径或任意数量的路径段。
应用路由中的可选Catch-all路由
文件路径结构:
app/
posts/
[[...slug]]/ // 可选动态参数 slug
page.tsx // 对应 /posts 或 /posts/任意路径段
组件示例:
tsx
// app/posts/[[...slug]]/page.tsx
export default function PostsPage({ params }) {
const { slug } = params || [];
return (
<div>
<h1>文章路径:{slug.length ? slug.join('/') : '最新文章'}</h1>
<p>这是文章列表页面。</p>
</div>
);
}
页面路由中的可选Catch-all路由
文件路径结构:
pages/
posts/
[[...slug]].js // 可选动态参数 slug
组件示例:
jsx
// pages/posts/[[...slug]].js
import {路由器} from 'next/router';
export default function PostsPage() {
const router =路由器();
const { slug } = router.query; // slug可能为undefined或数组
return (
<div>
<h1>文章路径:{slug ? slug.join ( '/' ) : '最新文章'}</h1>
<p>这是文章列表页面。</p>
</div>
);
}
四、API路由:创建服务器端API端点
Next.js允许开发者在前端项目中创建API路由,无需额外搭建Node.js服务器。两种路由系统都支持API路由,但实现方式有所不同。
应用路由中的API路由
在应用路由系统中,API路由通过在app/api/目录下创建route.js文件实现。
文件路径结构:
app/
api/
users/
route.js // 对应 /api/users
posts/
[...slug]/ // 动态参数 slug
route.js // 对应 /api/posts/任意路径段
组件示例:
tsx
// app/api/users/route.js
export async function GET(request) {
const response = await fetch('https://api.example.com/users');
const users = await response.json();
return new Response(JSON.stringify(users), {
headers: { 'Content-Type': 'application/json' },
});
}
// app/api/posts/[...slug]/route.js
export async function GET({ params }) {
const { slug } = params; // slug是一个数组
const path = slug.join ( '/' );
const response = await fetch(`https://api.example.com/posts/${path}`);
const post = await response.json();
if (!post) {
return new Response('Not Found', { status: 404 });
}
return new Response(JSON.stringify(post), {
headers: { 'Content-Type': 'application/json' },
});
}
// 处理POST请求的示例
export async function POST(request) {
const data = await request.json();
// 数据处理逻辑...
return new Response('Success', { status: 200 });
}
页面路由中的API路由
在页面路由系统中,API路由通过在pages/api/目录下创建普通JS文件实现。
文件路径结构:
pages/
api/
users.js // 对应 /api/users
posts/
[...slug].js // 动态参数 slug,对应 /api/posts/任意路径段
组件示例:
jsx
// pages/api/users.js
export default function handler(req, res) {
// 处理GET请求
if (req.method === 'GET') {
res.status(200).json({ message: '用户列表' });
}
// 处理POST请求
else if (req.method === 'POST') {
const { name, email } = req.body;
// 创建用户逻辑...
res.status(201).json({ message: '用户创建成功' });
}
// 不支持的请求方法
else {
res.status(405).json({ error: 'Method Not Allowed' });
}
}
动态参数API路由示例:
jsx
// pages/api/posts/[...slug].js
export default function handler(req, res) {
const { slug } = req.query; // slug是一个数组
const path = slug.join ( '/' );
// 根据路径获取文章...
const post = await getPostByPath(path);
if (!post) {
res.status(404).json({ error: '文章不存在' });
}
res.status(200).json(post);
}
API路由的配置对象
页面路由系统允许通过config对象自定义API路由行为,如设置请求体大小限制等。
jsx
// pages/api/submit.js
export const config = {
api: {
// 设置请求体大小限制
sizeLimit: '2mb',
// 其他配置选项...
}
};
export default function handler(req, res) {
// 处理请求逻辑...
}
五、路由嵌套与布局组件:构建一致的UI结构
路由嵌套和布局组件是Next.js路由系统的重要特性,它们允许开发者构建层次化的UI结构。
应用路由中的路由嵌套与布局组件
在应用路由系统中,路由嵌套通过目录层级实现,布局组件通过layout.tsx文件定义,支持多级嵌套。
文件路径结构:
app/
layout.tsx // 全局布局
page.tsx // 根页面
blog/
layout.tsx // 博客局部布局
page.tsx // /blog页面
[id]/ // 动态参数 id
layout.tsx // 博客文章局部布局
page.tsx // /blog/123页面
comments/
layout.tsx // 评论局部布局
page.tsx // /blog/123/comments页面
全局布局组件:
tsx
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<head>
<title>我的博客</title>
<meta name="description" content="一个技术博客网站" />
</head>
<body>
<Header />
<main>{children}</main>
<Footer />
</body>
</html>
);
}
局部布局组件:
tsx
// app/blog/layout.tsx
export default function BlogLayout({ children }) {
return (
<div className="blog-container">
<BlogHeader />
<侧边栏 />
<main>{children}</main>
</div>
);
}
嵌套路由的渲染顺序 :
当访问/blog/123/comments时,Next.js会按以下顺序渲染布局组件:
- 全局布局(app/layout.tsx)
- 博客布局(app/blog/layout.tsx)
- 文章布局(app/blog/[id]/layout.tsx)
- 评论布局(app/blog/[id]/comments/layout.tsx)
- 评论页面(app/blog/[id]/comments/page.tsx)
页面路由中的路由嵌套与布局组件
在页面路由系统中,路由嵌套通过文件夹结构实现,但布局组件只能通过全局_app.js实现,无法支持局部嵌套布局。
文件路径结构:
pages/
index.js // 根路径 /
about.js // /about
blog/
index.js // /blog
[id].js // /blog/123
comments/
index.js // /blog/123/comments
全局布局组件:
jsx
// pages/_app.js
import React from 'react';
import App from 'next/app';
import Header from '../components common/Header';
import Footer from '../components common/Footer';
export default function MyApp({ Component, pageProps }) {
return (
<div className="app-container">
<Header />
<Component {...pageProps} />
<Footer />
</div>
);
}
手动实现局部布局 :
由于页面路由系统不支持局部布局组件,开发者通常通过高阶组件(HOC)或使用use wraps 钩子手动实现局部布局:
jsx
// components/blog Layout.js
import React from 'react';
const BlogLayout = ({ children }) => {
return (
<div className="blog-container">
<BlogHeader />
<侧边栏 />
<main>{children}</main>
</div>
);
};
export default BlogLayout;
jsx
// pages/blog/[id].js
import BlogLayout from '../components/blog Layout';
const BlogPost = () => {
return (
<BlogLayout>
<div>这是博客文章页面</div>
</BlogLayout>
);
};
export default BlogPost;
六、路由导航:在应用中实现页面跳转
Next.js提供了多种方式实现路由导航,包括客户端组件和服务器组件中的导航。
应用路由中的路由导航
在应用路由系统中,路由导航主要通过next/navigation模块中的钩子实现。
使用Link组件导航:
tsx
// 客户端导航
import Link from 'next/navigation';
function BlogList() {
const posts = await getPosts(); // 服务端数据获取
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href `/blog/${post.id}`}>
{post.title}
</Link>
</li>
))}
</ul>
);
}
使用useRouter钩子编程式导航:
tsx
// 客户端导航
import {路由器} from 'next/navigation';
function UserActions() {
const router =路由器();
const handleEdit = async () => {
const { id } = await routerSearchParams; // 获取当前路由参数
router.push `/users/${id}/edit`; // 跳转到编辑页面
};
return <button onClick={handleEdit}>编辑资料</button>;
}
服务端导航 :
在服务器组件中,可以直接使用Response对象进行重定向:
tsx
// app/dashboard/route.js
export async function GET() {
const session = await checkSession();
if (!session) {
return NextResponse redirect('/login', { status: 307 });
}
// 返回正常响应...
}
页面路由中的路由导航
在页面路由系统中,路由导航主要通过next/router模块中的钩子实现。
使用Link组件导航:
jsx
// 客户端导航
import Link from 'next/router';
function BlogList() {
const posts = await getPosts(); // 服务端数据获取
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href `/blog/${post.id}`}>
{post.title}
</Link>
</li>
))}
</ul>
);
}
使用useRouter钩子编程式导航:
jsx
// 客户端导航
import {路由器} from 'next/router';
function UserActions() {
const router =路由器();
const handleEdit = () => {
const { id } = router.query; // 获取当前路由参数
router.push `/users/${id}/edit`; // 跳转到编辑页面
};
return <button onClick={handleEdit}>编辑资料</button>;
}
服务端导航 :
在页面路由系统中,服务端导航通常通过返回redirect对象实现:
jsx
// pages/dashboard.js
export async function getServerSideProps() {
const session = await checkSession();
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
return {
props: {}, // 传递给页面组件的props
};
}
七、路由权限控制:保护敏感页面
路由权限控制是确保敏感页面只能被授权用户访问的重要机制。Next.js提供了多种实现方式。
应用路由中的权限控制
在应用路由系统中,权限控制主要通过中间件实现,这是一种高效且集中式的解决方案。
中间件实现权限控制:
tsx
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
const protectedRoutes = [
'/dashboard',
'/profile',
'/admin',
];
const publicRoutes = [
'/',
'/login',
'/signup',
];
export default async function authMiddleware(
request: NextRequest
) {
const path = request.nextUrl.pathname;
const isProtected = protectedRoutes.some(
(route) => path.startsWith(route)
);
const isPublic = publicRoutes.includes(path);
// 获取用户会话信息
const session = await checkSession(request);
// 保护路由检查
if (isProtected && !session userId ) {
return NextResponse redirect(
new URL('/login', request.nextUrl),
{ status: 307 }
);
}
// 公共路由检查
if (isPublic && session userId ) {
return NextResponse redirect(
new URL('/dashboard', request.nextUrl),
{ status: 307 }
);
}
return NextResponse.next();
}
export const config = {
matcher: '/((?!api|_next|.*\\.(?:css|js|png|jpg|svg)).*)',
};
在路由组件中检查权限:
tsx
// app/dashboard/page.tsx
import {路由器} from 'next/navigation';
export default async function DashboardPage() {
const router =路由器();
// 获取用户会话信息
const session = await checkSession();
// 未登录用户重定向
if (!session userId ) {
router.push('/login');
return null; // 阻止渲染
}
// 获取仪表板数据...
const data = await getDashboardData();
return (
<div>
<h1>仪表板</h1>
<p>这是您的个人仪表板。</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
页面路由中的权限控制
在页面路由系统中,权限控制可以通过服务端获取函数或客户端组件实现。
使用getServerSideProps检查权限:
jsx
// pages/dashboard.js
export async function getServerSideProps(context) {
const session = await checkSession(context);
if (!session userId ) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
// 获取仪表板数据...
const data = await getDashboardData();
return {
props: { data }, // 传递给页面组件的props
};
}
export default function Dashboard({ data }) {
return (
<div>
<h1>仪表板</h1>
<p>这是您的个人仪表板。</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
使用客户端组件检查权限:
jsx
// pages/dashboard.js
进口' use client '
import {路由器} from 'next/router';
import { useEffect } from 'react';
export default function Dashboard() {
const router =路由器();
useEffect(() => {
const checkAuth = async () => {
const session = await checkSession();
if (!session userId ) {
router.push('/login');
}
};
checkAuth();
}, []);
return (
<div>
<h1>仪表板</h1>
<p>这是您的个人仪表板。</p>
</div>
);
}
八、路由重定向:处理URL变更
路由重定向是处理URL变更的重要机制,Next.js提供了多种实现方式。
应用路由中的重定向
在应用路由系统中,重定向可以通过redirect()函数或中间件实现。
服务端组件中的重定向:
tsx
// app/dashboard/page.tsx
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await checkSession();
if (!session userId ) {
redirect('/login'); // 307临时重定向
}
return <div>仪表板内容</div>;
}
中间件中的重定向:
tsx
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export default function oldUrlRedirect(request: NextRequest) {
const url = request.nextUrl.pathname;
// 将/old-path重定向到/new-path
if (url === '/old-path') {
return NextResponse redirect('/new-path', {
status: 308, // 308永久重定向
});
}
return NextResponse.next();
}
export const config = {
matcher: '/old-path',
};
页面路由中的重定向
在页面路由系统中,重定向可以通过服务端获取函数或客户端组件实现。
服务端获取函数中的重定向:
jsx
// pages/dashboard.js
export async function getServerSideProps(context) {
const session = await checkSession(context);
if (!session userId ) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
return {
props: {}, // 传递给页面组件的props
};
}
客户端组件中的重定向:
jsx
// pages/dashboard.js
进口' use client '
import {路由器} from 'next/router';
import { useEffect } from 'react';
export default function Dashboard() {
const router =路由器();
useEffect(() => {
const checkAuth = async () => {
const session = await checkSession();
if (!session userId ) {
router.push('/login');
}
};
checkAuth();
}, []);
return <div>仪表板内容</div>;
}
九、路由优化:提升应用性能
Next.js提供了多种路由优化技术,帮助开发者提升应用性能。
应用路由中的路由优化
在应用路由系统中,路由优化主要通过并行数据获取、流式渲染和增量静态再生成(ISR)实现。
并行数据获取:
tsx
// app/dashboard/page.tsx
export default async function DashboardPage() {
const [user, posts] = await Promise.all([
fetch('https://api.example.com/user'),
fetch('https://api.example.com/posts'),
]);
return (
<div>
<h1>仪表板</h1>
<p>欢迎,{user.name}</p>
<h2>最新帖子</h2>
<ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>
</div>
);
}
流式渲染:
tsx
// app/blog/[id]/page.tsx
import {路由器} from 'next/navigation';
export default async function BlogPost({ params }) {
const { id } = await params;
// 先返回部分HTML内容
const initialContent = (
<div>
<h1>加载中...</h1>
<p>正在获取文章内容...</p>
</div>
);
// 在后台获取数据
const response = await fetch(`https://api.example.com/blog/${id}`);
const post = await response.json();
// 返回完整内容
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
增量静态再生成(ISR):
tsx
// app/blog/[id]/page.tsx
import {路由器} from 'next/navigation';
export default async function BlogPost({ params }) {
const { id } = await params;
// 获取文章内容
const post = await getPost(id);
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
// 启用ISR,每30分钟更新一次
export const revalidate = 30; // 秒
页面路由中的路由优化
在页面路由系统中,路由优化主要通过静态生成(SSG)、服务器端渲染(SSR)和预加载(Prefetching)实现。
静态生成(SSG):
jsx
// pages/blog/[id].js
export async function getStaticProps({ params }) {
const id = params.id;
// 获取文章内容
const post = await getPost(id);
return {
props: { post }, // 传递给页面组件的props
revalidate: 30, // 启用ISR,每30秒更新一次
};
}
export async function getStaticPaths() {
// 获取所有可能的文章ID
const posts = await getPosts();
// 生成静态路径
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
// 允许生成未预先渲染的路径
return {
paths,
fallback: true,
};
}
服务器端渲染(SSR):
jsx
// pages/dashboard.js
export async function getServerSideProps(context) {
const session = await checkSession(context);
if (!session userId ) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
// 获取仪表板数据...
const data = await getDashboardData();
return {
props: { data }, // 传递给页面组件的props
};
}
预加载(Prefetching):
jsx
// pages/blog.js
import Link from 'next/router';
function BlogList() {
// 预加载链接
const links = posts.map((post) => (
<Link href `/blog/${post.id}`} key={post.id}>
{post.title}
</Link>
));
return <div>{links}</div>;
}
十、路由与SEO:提高搜索引擎排名
路由设计对SEO有重要影响,Next.js提供了多种优化SEO的路由策略。
应用路由与SEO
应用路由系统默认支持服务端渲染(SSR),这对SEO非常友好。通过合理设计路由结构和使用ISR,开发者可以构建既高性能又SEO友好的应用。
服务端渲染(SSR)示例:
tsx
// app/blog/[id]/page.tsx
export default async function BlogPost({ params }) {
const { id } = await params;
// 获取文章内容
const post = await getPost(id);
return (
<html>
<head>
<title>{post.title}</title>
<meta name="description" content={post摘要} />
</head>
<body>
<文章标题={post.title}内容={post.content} />
</body>
</html>
);
}
静态生成(SSG)示例:
tsx
// app/blog/[id]/page.tsx
export default function BlogPost({ post }) {
return (
<html>
<head>
<title>{post.title}</title>
<meta name="description" content={post摘要} />
</head>
<body>
<文章标题={post.title}内容={post.content} />
</body>
</html>
);
}
export async function generateStaticParams() {
// 获取所有可能的文章ID
const posts = await getPosts();
// 生成静态路径
return posts.map((post) => ({
params: { id: post.id.toString() },
}));
}
页面路由与SEO
页面路由系统也支持多种SEO优化策略,但需要开发者手动实现。
服务端渲染(SSR)示例:
jsx
// pages/blog/[id].js
export async function getServerSideProps(context) {
const id = context.params.id;
// 获取文章内容
const post = await getPost(id);
return {
props: { post }, // 传递给页面组件的props
};
}
export default function BlogPost({ post }) {
return (
<html>
<head>
<title>{post.title}</title>
<meta name="description" content={post摘要} />
</head>
<body>
<文章标题={post.title}内容={post.content} />
</body>
</html>
);
}
静态生成(SSG)示例:
jsx
// pages/blog/[id].js
export async function getStaticProps({ params }) {
const id = params.id;
// 获取文章内容
const post = await getPost(id);
return {
props: { post }, // 传递给页面组件的props
};
}
export async function getStaticPaths() {
// 获取所有可能的文章ID
const posts = await getPosts();
// 生成静态路径
return {
paths: posts.map((post) => ({
params: { id: post.id.toString() },
})),
fallback: false, // 禁用客户端回退
};
}
export default function BlogPost({ post }) {
return (
<html>
<head>
<title>{post.title}</title>
<meta name="description" content={post摘要} />
</head>
<body>
<文章标题={post.title}内容={post.content} />
</body>
</html>
);
}
十一、路由与国际化:支持多语言应用
Next.js提供了强大的国际化支持,允许开发者构建支持多语言的应用。
应用路由中的国际化
在应用路由系统中,国际化通过next-intl等第三方库实现,支持动态语言切换和本地化路由。
国际化配置示例:
tsx
// app/i18n.js
import { createIntlServer } from 'next-intl/server';
export async function阻力() {
const { locale } = router.query;
// 创建国际化服务器
const server = await createIntlServer({
defaultLocale: 'en',
locales: ['en', 'zh'],
messages: {
en: await import ('./messages/en.json'),
zh: await import ('./messages/zh.json'),
},
});
return {
props: { server },
};
}
多语言路由示例:
tsx
// app/[locale]/blog/[id]/page.tsx
import {路由器} from 'next/navigation';
export default async function BlogPost({ params }) {
const { locale, id } = await params;
// 获取文章内容
const post = await getPost(id, locale);
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
页面路由中的国际化
在页面路由系统中,国际化通过next-i18next等第三方库实现,同样支持多语言应用。
国际化配置示例:
jsx
// next-i18next.config.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import en from './messages/en.json';
import zh from './messages/zh.json';
const resources = {
en: { translation: en },
zh: { translation: zh },
};
const i18nConfig = {
resources,
detection: { order: ['navigator'] },
interpolation: { escapeValue: false },
fallbackLng: 'en',
initialI18nStore: true,
use: [initReactI18next],
};
export default i18n.use(i18nConfig);
多语言路由示例:
jsx
// pages/[locale]/blog/[id].js
import {路由器} from 'next/router';
import i18n from '../next-i18next.config';
export default function BlogPost() {
const router =路由器();
const { locale, id } = router.query;
// 获取文章内容
const post = await getPost(id, locale);
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
十二、路由与状态管理:维护应用状态
路由与状态管理是构建复杂应用的关键,Next.js提供了多种方式实现路由状态管理。
应用路由中的状态管理
在应用路由系统中,状态管理可以通过React Context API、Zustand或Recoil等库实现,与路由系统无缝集成。
使用Context API管理路由状态:
tsx
// app context/ navigation. tsx
import {路由器} from 'next/navigation';
import { createContext, useState } from 'react';
export const NavigationContext = createContext(null);
export const NavigationProvider = ({ children }) => {
const router =路由器();
const [currentRoute, setCurrentRoute] = useState(router.pathname);
// 监听路由变化
useEffect(() => {
const handleRouteChange = (url) => {
setCurrentRoute(url);
};
router events. on('routeChangeComplete', handleRouteChange);
return () => {
router events. off('routeChangeComplete', handleRouteChange);
};
}, []);
return (
<NavigationContext.Provider value={{ currentRoute }}>
{children}
</NavigationContext.Provider>
);
};
在布局组件中使用状态:
tsx
// app/layout.tsx
import {路由器} from 'next/navigation';
import { NavigationContext } from './context/navigation';
export default function RootLayout({ children }) {
const { currentRoute } = React . useContext (NavigationContext);
return (
<html>
<head>
<title>我的博客 - {currentRoute}</title>
</head>
<body>
<Header currentRoute={currentRoute} />
<main>{children}</main>
<Footer />
</body>
</html>
);
}
页面路由中的状态管理
在页面路由系统中,状态管理同样可以通过Context API或状态管理库实现,但需要额外配置。
使用Context API管理路由状态:
jsx
// pages/_app.js
import React from 'react';
import App from 'next/app';
import {路由器} from 'next/router';
import { createContext, useState } from 'react';
export const NavigationContext = createContext(null);
export default function MyApp({ Component, pageProps }) {
const [currentRoute, setCurrentRoute] = useState('/');
// 监听路由变化
useEffect(() => {
const handleRouteChange = (url) => {
setCurrentRoute(url);
};
路由器. onRouteChangeComplete(handleRouteChange);
return () => {
路由器. offRouteChangeComplete(handleRouteChange);
};
}, []);
return (
<NavigationContext.Provider value={{ currentRoute }}>
<div className="app-container">
<Header currentRoute={currentRoute} />
<Component {...pageProps} />
<Footer />
</div>
</NavigationContext.Provider>
);
}
十三、路由与数据获取:结合API与页面数据
路由与数据获取的结合是构建数据驱动应用的关键,Next.js提供了多种方式实现路由相关的数据获取。
应用路由中的数据获取
在应用路由系统中,数据获取可以直接在组件中使用fetch函数,无需额外导出函数。
服务端数据获取:
tsx
// app/blog/[id]/page.tsx
export default async function BlogPost({ params }) {
const { id } = await params;
// 获取文章内容
const postResponse = await fetch(`https://api.example.com/blog/${id}`);
const post = await postResponse.json();
// 获取评论
const commentsResponse = await fetch(`https://api.example.com/blog/${id}/comments`);
const comments = await commentsResponse.json();
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
<h2>评论</h2>
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
</div>
);
}
并行数据获取:
tsx
// app/dashboard/page.tsx
export default async function DashboardPage() {
const [user, posts] = await Promise.all([
fetch('https://api.example.com/user'),
fetch('https://api.example.com/posts'),
]);
return (
<div>
<h1>仪表板</h1>
<p>欢迎,{user.name}</p>
<h2>最新帖子</h2>
<ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>
</div>
);
}
页面路由中的数据获取
在页面路由系统中,数据获取主要通过getServerSideProps或getStaticProps实现。
服务端数据获取:
jsx
// pages/blog/[id].js
export async function getServerSideProps(context) {
const id = context.params.id;
// 获取文章内容
const postResponse = await fetch(`https://api.example.com/blog/${id}`);
const post = await postResponse.json();
// 获取评论
const commentsResponse = await fetch(`https://api.example.com/blog/${id}/comments`);
const comments = await commentsResponse.json();
return {
props: { post, comments }, // 传递给页面组件的props
};
}
export default function BlogPost({ post, comments }) {
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
<h2>评论</h2>
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
</div>
);
}
静态生成数据获取:
jsx
// pages/blog/[id].js
export async function getStaticProps({ params }) {
const id = params.id;
// 获取文章内容
const postResponse = await fetch(`https://api.example.com/blog/${id}`);
const post = await postResponse.json();
// 获取评论
const commentsResponse = await fetch(`https://api.example.com/blog/${id}/comments`);
const comments = await commentsResponse.json();
return {
props: { post, comments }, // 传递给页面组件的props
revalidate: 60, // 启用ISR,每60秒更新一次
};
}
export async function getStaticPaths() {
// 获取所有可能的文章ID
const posts = await getPosts();
// 生成静态路径
return {
paths: posts.map((post) => ({
params: { id: post.id.toString() },
})),
fallback: true, // 允许客户端回退
};
}
export default function BlogPost({ post, comments }) {
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
<h2>评论</h2>
<ul>
{comments.map((comment) => (
<li key={comment.id}>{comment.content}</li>
))}
</ul>
</div>
);
}
十四、路由与边缘计算:构建全球分布式应用
Next.js 14+版本引入了边缘计算支持,允许开发者将路由逻辑部署到全球边缘节点,提供更快速的访问体验。
应用路由中的边缘计算
在应用路由系统中,边缘计算通过在路由组件中使用fetch函数并设置next羰基物来实现。
边缘计算路由示例:
tsx
// app/blog/[id]/page.tsx
import {路由器} from 'next/navigation';
export default async function BlogPost({ params }) {
const { id } = await params;
// 使用边缘计算获取数据
const post = await fetch(`https://api.example.com/blog/${id}`, {
next: { revalidate: 60 }, // 缓存60秒
});
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
页面路由中的边缘计算
在页面路由系统中,边缘计算同样通过fetch函数的next羰基物实现,但需要在服务端获取函数中使用。
边缘计算路由示例:
jsx
// pages/blog/[id].js
export async function getServerSideProps(context) {
const id = context.params.id;
// 使用边缘计算获取数据
const postResponse = await fetch(`https://api.example.com/blog/${id}`, {
next: { revalidate: 60 }, // 缓存60秒
});
const post = await postResponse.json();
return {
props: { post }, // 传递给页面组件的props
};
}
export default function BlogPost({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>作者:{post.author}</p>
<div危及={post.content} />
</div>
);
}
十五、路由与错误处理:优雅应对异常情况
路由与错误处理是构建健壮应用的关键,Next.js提供了多种机制处理路由相关的错误。
应用路由中的错误处理
在应用路由系统中,错误处理主要通过error.tsx组件和中间件实现。
全局错误处理:
tsx
// app/error.tsx
import {路由器} from 'next/navigation';
export default function ErrorPage() {
const { error } =路由器();
return (
<div>
<h1>错误</h1>
<p>{error.message}</p>
<button onClick={() =>路由器.push('/')}>返回首页</button>
</div>
);
}
局部错误处理:
tsx
// app/blog/[id]/error.tsx
import {路由器} from 'next/navigation';
export default function BlogErrorPage() {
const { error } =路由器();
return (
<div>
<h1>博客文章错误</h1>
<p>{error.message}</p>
<button onClick={() =>路由器.push('/blog')}>返回博客列表</button>
</div>
);
}
中间件错误处理:
tsx
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export default function errorHandlingMiddleware(
request: NextRequest
) {
try {
// 执行可能出错的逻辑...
} catch (error) {
return NextResponse redirect('/error', {
status: 307,
});
}
return NextResponse.next();
}
页面路由中的错误处理
在页面路由系统中,错误处理主要通过_error.js组件实现,但需要手动处理特定错误。
全局错误处理:
jsx
// pages/_error.js
import {路由器} from 'next/router';
export default function ErrorPage({ res }) {
const { err } =路由器();
return (
<div>
<h1>错误</h1>
<p>{err.message}</p>
<button onClick={() =>路由器.push('/')}>返回首页</button>
</div>
);
}
十六、路由与性能监控:优化应用性能
路由与性能监控是确保应用高性能的关键,Next.js提供了多种工具和机制监控路由性能。
应用路由中的性能监控
在应用路由系统中,性能监控可以通过Next.js内置的性能分析工具和自定义中间件实现。
使用内置性能分析工具:
jsx
// 在next.config.js中启用性能分析
module.exports = {
experimental: {
appDir: true,
},
future: {
strictRouterState: true,
},
trailingSlashes: true,
swcMinify: true,
// 启用性能分析
analyze: true,
};
自定义中间件监控路由性能:
tsx
// app/middleware.js
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export default function performanceMiddleware(
request: NextRequest
) {
const start = Date . now();
return NextResponse.next(). finally(() => {
const duration = Date . now() - start;
console.log(`路由 ${request.nextUrl.pathname} 耗时 ${duration}ms`);
});
}
页面路由中的性能监控
在页面路由系统中,性能监控可以通过Next.js内置的性能分析工具和自定义代码实现。
使用内置性能分析工具:
jsx
// 在next.config.js中启用性能分析
module.exports = {
// 启用性能分析
analyze: true,
// 其他配置...
};
自定义代码监控路由性能:
jsx
// pages/_app.js
import React, { useEffect } from 'react';
import App from 'next/app';
import {路由器} from 'next/router';
export default function MyApp({ Component, pageProps }) {
useEffect(() => {
const handleRouteChange = (url) => {
console.log(`路由变更:${url},时间:${new Date().toISOString()}`);
};
路由器. onRouteChangeComplete(handleRouteChange);
return () => {
路由器. offRouteChangeComplete(handleRouteChange);
};
}, []);
return (
<div className="app-container">
<Component {...pageProps} />
</div>
);
}
十七、路由与第三方库集成:扩展路由功能
路由与第三方库集成是构建复杂应用的重要能力,Next.js支持多种第三方路由库和工具。
应用路由与第三方库集成
在应用路由系统中,可以集成next connect等库增强API路由功能。
使用next connect增强API路由:
jsx
// app/api/users/route.js
import { NextResponse } from 'next/server';
import { NextConnect } from 'next connect';
const connect = NextConnect();
connect.use((req, res, next) => {
console.log('请求到达:', req.nextUrl.pathname);
next();
});
connect.get(async (req, res) => {
const users = await fetchUsers();
return NextResponse.json(users);
});
connect.post(async (req, res) => {
const data = await req.json();
// 创建用户逻辑...
return NextResponse.json({ message: '用户创建成功' });
});
export default connect;
页面路由与第三方库集成
在页面路由系统中,可以集成react router dom等库实现更复杂的路由逻辑。
使用react router dom增强路由功能:
jsx
// pages/_app.js
import React from 'react';
import App from 'next/app';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Router history={history}>
<Component {...pageProps} />
</Router>
);
}
}
十八、路由与测试:确保路由功能正确性
路由与测试是确保应用质量的重要环节,Next.js提供了多种测试路由功能的方法。
应用路由测试
在应用路由系统中,可以使用next testing library和react testing library测试路由功能。
测试动态路由组件:
jsx
// tests/blog Post Test. tsx
import {渲染,屏幕} from '@testing library / react';
import {路由器} from 'next/navigation';
// 模拟路由器
const mockRouter = {
push: vi.fn(),
replace: vi.fn(),
query: { id: '123' },
};
vi.mock('next/navigation', () => ({
路由器: () => mockRouter,
useParams: () => ({ id: '123' }),
redirect: vi.fn(),
permanentRedirect: vi.fn(),
}));
describe('博客文章页面', () => {
it('渲染文章标题和内容', async () => {
// 模拟获取文章数据
vi mock.('fetch', vi.fn().mockImplementationOnce(() =>
Promise.resolve({
json: () => Promise.resolve({ title: '测试文章', content: '测试内容' }),
})
));
渲染(<BlogPostPage params={{ id: '123' }} />);
expect await (screen.findByText('测试文章')).toBeInTheDocument();
expect await (screen.findByText('测试内容')).toBeInTheDocument();
});
it('处理文章不存在的情况', async () => {
// 模拟获取不存在的文章
vi mock.('fetch', vi.fn().mockImplementationOnce(() =>
Promise.resolve({
json: () => Promise.resolve(null),
})
));
渲染(<BlogPostPage params={{ id: '123' }} />);
expect await (screen.findByText('文章不存在')).toBeInTheDocument();
});
});
页面路由测试
在页面路由系统中,同样可以使用next testing library和react testing library测试路由功能。
测试动态路由组件:
jsx
// tests/blog Post Test. tsx
import {渲染,screen} from '@testing library / react';
import {路由器} from 'next/router';
// 模拟路由器
const mockRouter = {
push: vi.fn(),
replace: vi.fn(),
query: { id: '123' },
};
vi.mock('next/router', () => ({
路由器: () => mockRouter,
useEffect: vi.fn(),
useLayoutEffect: vi.fn(),
Link: vi.fn().mockImplementation(({ href, children }) => (
<a href={href}>{children}</a>
)),
// 模拟getServerSideProps
getServerSideProps: vi.fn().mockImplementationOnce(() =>
Promise.resolve({
props: { post: { title: '测试文章', content: '测试内容' } },
})
),
}));
describe('博客文章页面', () => {
it('渲染文章标题和内容', () => {
渲染(<BlogPostPage post={{ title: '测试文章', content: '测试内容' }} />);
expect(screen.findByText('测试文章')).toBeInTheDocument();
expect(screen.findByText('测试内容')).toBeInTheDocument();
});
it('处理文章不存在的情况', () => {
// 模拟getServerSideProps返回notFound
vi mock.('getServerSideProps', vi.fn().mockImplementationOnce(() =>
Promise.resolve({ notFound: true })
));
渲染(<BlogPostPage post={{}} />);
expect(screen.findByText('页面未找到')).toBeInTheDocument();
});
});
十九、路由与部署:将应用部署到生产环境
路由与部署是将开发完成的应用推向用户的关键环节,Next.js提供了多种部署选项和优化策略。
应用路由部署
应用路由系统与Next.js的部署流程兼容,可以部署到Vercel、AWS、Google Cloud等平台。
部署到Vercel:
jsx
// vercel.json
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@next刀片"
}
],
"routes": [
{
"src": "/((?!_next/|api/).*)",
"dest": "/app/index.js"
},
{
"src": "/api/(.*)",
"dest": "/pages/api/index.js"
}
]
}
页面路由部署
页面路由系统同样支持多种部署选项,但需要注意一些特定配置。
部署到AWS:
jsx
// next.config.js
module.exports = {
experimental: {
appDir: true,
},
trailingSlashes: true,
swcMinify: true,
// AWS部署配置
assetPrefix: process.env.NEXT Public Prefix,
distDir: 'dist',
generateBuildId: async () => 'build-' + Date . now().toString(),
};
二十、路由与版本控制:管理路由变更
路由与版本控制是管理应用演进的重要能力,Next.js提供了多种路由版本控制策略。
应用路由版本控制
在应用路由系统中,可以通过目录层级实现路由版本控制。
版本控制路由结构:
app/
api/
v1/
users/
route.js // /api/v1/users
v2/
users/
route.js // /api/v2/users
页面路由版本控制
在页面路由系统中,可以通过路径命名实现路由版本控制。
版本控制路由结构:
pages/
api/
v1/
users.js // /api/v1/users
v2/
users.js // /api/v2/users
二十一、路由与微前端:构建模块化应用
路由与微前端是构建大型模块化应用的重要策略,Next.js支持通过路由系统集成微前端组件。
应用路由微前端集成
在应用路由系统中,可以通过目录层级和动态路由实现微前端集成。
微前端路由结构:
app/
micro/
[module]/ // 动态模块参数
[component]/ // 动态组件参数
page.tsx // 对应 /micro/module/component
微前端组件示例:
tsx
// app/micro/[module]/[component]/page.tsx
import {路由器} from 'next/navigation';
export default async function MicroFrontendPage({ params }) {
const { module, component } = await params;
// 动态加载微前端组件
const MicroComponent = await import(`./micro/${module}/${component}.tsx`);
return <MicroComponent default />;
}
页面路由微前端集成
在页面路由系统中,可以通过路径命名和组件动态加载实现微前端集成。
微前端路由结构:
pages/
micro/
[module]/ // 动态模块参数
[component]/ // 动态组件参数
index.js // 对应 /micro/module/component
微前端组件示例:
jsx
// pages/micro/[module]/[component]/index.js
import {路由器} from 'next/router';
export default function MicroFrontendPage() {
const router =路由器();
const { module, component } = router.query;
// 动态加载微前端组件
const MicroComponent = require(`./micro/${module}/${component}.jsx`). default;
return <MicroComponent />;
}
二十二、路由与渐进式Web应用(PWA):构建离线体验
路由与PWA是提供离线体验和推送通知的重要策略,Next.js支持通过路由系统构建PWA应用。
应用路由PWA集成
在应用路由系统中,可以通过next/pwa和workbox构建PWA应用。
PWA配置示例:
jsx
// next.config.js
module.exports = {
experimental: {
appDir: true,
},
future: {
strictRouterState: true,
},
trailingSlashes: true,
swcMinify: true,
// PWA配置
pwa: {
dest: 'public',
register: true,
skipWait: true,
updateOnLoad: true,
},
// 其他配置...
};
Service Worker路由缓存:
jsx
// public/service worker.js
import { workbox } from 'workbox';
// 缓存静态路由
workbox. strategies. cacheFirst({
cacheName: 'static-routes',
maxAgeSeconds: 30 * 24 * 60 * 60, // 30天
strategy: 'CacheFirst',
});
// 缓存动态路由
workbox. strategies. cacheWith策展人({
cacheName: 'dynamic-routes',
maxStaleSeconds: 60 * 60, // 1小时
strategy: 'CacheWith策展人',
});
页面路由PWA集成
在页面路由系统中,同样可以通过next/pwa和workbox构建PWA应用。
PWA配置示例:
jsx
// next.config.js
module.exports = {
// PWA配置
pwa: {
dest: 'public',
register: true,
skipWait: true,
updateOnLoad: true,
},
// 其他配置...
};
Service Worker路由缓存:
jsx
// public/service worker.js
import { workbox } from 'workbox';
// 缓存静态路由
workbox. strategies. cacheFirst({
cacheName: 'static-routes',
maxAgeSeconds: 30 * 24 * 60 * 0, // 30天
strategy: 'CacheFirst',
});
// 缓存动态路由
workbox. strategies. cacheWith策展人({
cacheName: 'dynamic-routes',
maxStaleSeconds: 60 * 60, // 1小时
strategy: 'CacheWith策展人',
});
二十三、路由与边缘缓存:提升全球访问速度
路由与边缘缓存是提升全球用户访问速度的重要策略,Next.js支持通过路由系统实现边缘缓存。
应用路由边缘缓存
在应用路由系统中,可以通过next羰基物和边缘计算实现路由边缘缓存。
边缘缓存路由示例:
jsx
// app/blog/[id]/route.js
export async function GET({ params }) {
const { id } = params;
// 获取文章内容
const post = await fetch(`https://api.example.com/blog/${id}`, {
next: { revalidate: 60 }, // 每60秒重新验证一次
});
return new Response post. json(), {
headers: { 'Content-Type': 'application/json' },
};
}
页面路由边缘缓存
在页面路由系统中,可以通过getServerSideProps和边缘计算实现路由边缘缓存。
边缘缓存路由示例:
jsx
// pages/blog/[id].js
export async function getServerSideProps(context) {
const id = context.params.id;
// 获取文章内容
const post = await fetch(`https://api.example.com/blog/${id}`, {
next: { revalidate: 60 }, // 每60秒重新验证一次
});
return {
props: { post }, // 传递给页面组件的props
};
}
二十四、路由与身份验证:保护用户数据
路由与身份验证是保护用户数据和实现用户权限管理的重要机制,Next.js支持通过路由系统实现身份验证。
应用路由身份验证
在应用路由系统中,身份验证可以通过中间件和服务器组件实现。
身份验证中间件:
jsx
// app/middleware.js
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export default function authMiddleware(request: NextRequest) {
// 检查认证状态
const session = request cookies. get('session');
if (!session) {
return NextResponse redirect('/login', {
status: 307,
});
}
return NextResponse.next();
}
受保护路由组件:
jsx
// app/dashboard/page.tsx
import {路由器} from 'next/navigation';
export default async function DashboardPage() {
const session = await checkSession();
if (!session userId ) {
redirect('/login');
}
// 获取仪表板数据...
const data = await getDashboardData();
return (
<div>
<h1>仪表板</h1>
<p>欢迎,{session userId }</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
页面路由身份验证
在页面路由系统中,身份验证可以通过服务端获取函数和客户端组件实现。
服务端身份验证:
jsx
// pages/dashboard.js
export async function getServerSideProps(context) {
const session = await checkSession(context);
if (!session userId ) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
// 获取仪表板数据...
const data = await getDashboardData();
return {
props: { data }, // 传递给页面组件的props
};
}
客户端身份验证:
jsx
// pages/dashboard.js
进口' use client '
import {路由器} from 'next/router';
import { useEffect } from 'react';
export default function Dashboard() {
const router =路由器();
useEffect(() => {
const checkAuth = async () => {
const session = await checkSession();
if (!session userId ) {
r