Next.js路由系统

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 通过getServerSidePropsgetStaticProps
路由导航 useParamsuseRouter 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会按以下顺序渲染布局组件:

  1. 全局布局(app/layout.tsx)
  2. 博客布局(app/blog/layout.tsx)
  3. 文章布局(app/blog/[id]/layout.tsx)
  4. 评论布局(app/blog/[id]/comments/layout.tsx)
  5. 评论页面(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>
  );
}
页面路由中的数据获取

在页面路由系统中,数据获取主要通过getServerSidePropsgetStaticProps实现。

服务端数据获取

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 libraryreact 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 libraryreact 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/pwaworkbox构建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/pwaworkbox构建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
相关推荐
程序员-小李1 小时前
基于 Python + OpenCV 的人脸识别系统开发实战
开发语言·python·opencv
QX_hao1 小时前
【Go】--文件和目录的操作
开发语言·c++·golang
卡提西亚1 小时前
C++笔记-20-对象特性
开发语言·c++·笔记
mapbar_front1 小时前
职场中的顶级能力—服务意识
前端
java1234_小锋2 小时前
[免费]基于Python的Flask酒店客房管理系统【论文+源码+SQL脚本】
开发语言·人工智能·python·flask·酒店客房
尽兴-2 小时前
[特殊字符] 微前端部署实战:Nginx 配置 HTTPS 与 CORS 跨域解决方案(示例版)
前端·nginx·https·跨域·cors·chrom
bubiyoushang8882 小时前
使用MATLAB计算梁单元的刚度矩阵和质量矩阵
开发语言·matlab·矩阵
三掌柜6662 小时前
C++ 零基础入门与冒泡排序深度实现
java·开发语言·c++
Yyyy4822 小时前
标签Labels、Scheduler:调度器、k8s污点与容忍度
开发语言·kubernetes