IT
📘

Next.js 15 App Router完全指南——服务器组件、数据获取与部署

USD/JPY分散は、為替急変局面で一方通貨の過大シェアを防ぎ、月次の再バランスと上限規則で感情的な一括投資を抑える実践設計です。

Next.js 15 App Router完全指南——服务器组件、数据获取与部署

> 核心摘要 Next.js 15引入了革命性的App Router架构,将React Server Components(RSC)作为默认范式。服务器组件在服务端运行,不向浏览器传输JavaScript,极大减少了bundle体积。fetch() API原生集成缓存系统,支持细粒度的ISR(增量静态再生)控制。流式传输(Streaming)和Suspense让页面局部渐进加载成为可能。理解服务器/客户端组件边界是掌握App Router的关键。

## 为什么App Router是架构升级

Next.js 13引入App Router,Next.js 15将其彻底成熟化。与Pages Router(pages/目录)相比,核心变化有以下几点:

特性Pages RouterApp Router
默认组件类型客户端组件服务器组件
数据获取getServerSideProps/getStaticPropsasync/await + fetch()
布局_app.tsx全局嵌套layout.tsx
路由文件即路由page.tsx即路由
流式传输不支持原生支持
元数据手动generateMetadata()

## 服务器组件 vs 客户端组件

### 服务器组件(默认)

``typescript // app/blog/page.tsx — 服务器组件(无需'use client') async function BlogPage() { const posts = await db.query('SELECT * FROM posts') // 直接数据库访问 return } ``

特点: - 在服务端执行,不向浏览器传输组件代码 - 可直接访问数据库、文件系统、内部API - 无法使用useStateuseEffect等React Hooks - 无法处理浏览器事件(onClick等)

### 客户端组件

```typescript 'use client' // 顶部声明,标记为客户端组件

import { useState } from 'react'

export function Counter() { const [count, setCount] = useState(0) return } ```

使用'use client'的场景: - useStateuseEffect等状态/副作用Hooks - 事件监听(onClick、onChange等) - 访问windowdocument等浏览器API - 第三方客户端库集成

### 组件边界设计原则

`` ServerComponent(服务器) └── ClientComponent(客户端)'use client' └── ServerComponent ❌ 不能在客户端组件内部导入服务器组件 ``

正确模式:通过props传递服务器数据给客户端组件

``typescript // ✅ 正确:服务器组件获取数据 → 传递给客户端组件 async function Page() { const data = await fetchData() return // 数据作为props传递 } ``

## 数据获取模式

### fetch()缓存控制

Next.js 15扩展了原生fetch(),支持细粒度缓存控制:

```typescript // 静态获取(构建时缓存,CDN分发) const data = await fetch('https://api.example.com/data', { cache: 'force-cache' // 默认值 })

// 动态获取(每次请求重新获取) const data = await fetch('https://api.example.com/data', { cache: 'no-store' })

// ISR:每3600秒重新验证 const data = await fetch('https://api.example.com/data', { next: { revalidate: 3600 } }) ```

### 路由级别缓存控制

``typescript // app/blog/page.tsx export const revalidate = 3600 // 整个路由每小时重新验证 export const dynamic = 'force-dynamic' // 强制动态渲染 export const dynamic = 'force-static' // 强制静态渲染 ``

### Suspense与流式传输

```typescript import { Suspense } from 'react'

export default function Page() { return (

页面标题(立即显示)

}> {/ 数据就绪后流式插入 /}
) } ```

流式传输让浏览器可以接收并渲染HTML块,而无需等待整个页面完成——TTFB(首字节时间)显著改善。

## 路由系统

### 文件系统路由约定

`` app/ ├── page.tsx → / ├── layout.tsx → 根布局(全局共享) ├── blog/ │ ├── page.tsx → /blog │ ├── [id]/ │ │ └── page.tsx → /blog/123 ├── (marketing)/ → 路由分组(URL中不显示) │ ├── layout.tsx → marketing专属布局 │ └── about/page.tsx → /about └── api/ └── posts/route.ts → API端点 GET/POST /api/posts ``

### 动态路由与params

``typescript // app/blog/[id]/page.tsx // Next.js 15: params是Promise,必须await export default async function BlogPost({ params, }: { params: Promise<{ id: string }> }) { const { id } = await params // ✅ 必须await const post = await getPost(id) return

{post.content}
} ``

### generateStaticParams(静态生成)

``typescript export async function generateStaticParams() { const posts = await getPosts() return posts.map(post => ({ id: String(post.id) })) } // 构建时预生成所有/blog/[id]页面 ``

## 性能优化

### Image组件优化

```typescript import Image from 'next/image'

描述性alt文本 ```

### Font优化

```typescript import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'], display: 'swap', }) // 字体自动优化:内联关键CSS,消除布局偏移 ```

### Metadata API

``typescript // app/blog/[id]/page.tsx export async function generateMetadata({ params, }: { params: Promise<{ id: string }> }): Promise { const { id } = await params const post = await getPost(id) return { title: post.title, description: post.description, openGraph: { images: [{ url: post.ogImage, width: 1200, height: 628 }], }, alternates: { canonical: https://example.com/blog/${id}, }, } } ``

## 部署策略

### Vercel(官方推荐)

``bash # 零配置部署 vercel deploy --prod ``

Vercel原生支持App Router所有特性:ISR、流式传输、边缘函数。

### Cloudflare Pages(OpenNext)

``bash # 使用@opennextjs/cloudflare适配器 npx @opennextjs/cloudflare build wrangler pages deploy .open-next ``

注意: Cloudflare Pages部署时,禁止使用export const runtime = 'edge'——OpenNext会统一处理所有路由。

## 常见问题(FAQ)

Q1. 什么时候必须使用'use client' 当组件需要使用useState/useEffect等React Hooks、处理浏览器事件、访问浏览器API(window/document)时,必须添加'use client'。数据展示类组件通常可以保持为服务器组件。

Q2. 服务器组件可以调用外部API吗? 可以。服务器组件可以直接await fetch()调用任何外部API,且可利用Next.js的缓存机制。敏感的API密钥不会暴露给客户端。

Q3. revalidateno-store的区别是什么? revalidate: N表示内容缓存N秒后重新验证(ISR模式),适合不需要实时更新的内容。cache: 'no-store'表示每次请求都重新获取,适合实时数据。

Q4. 如何在App Router中实现认证? 推荐使用middleware.ts拦截请求进行认证检查,配合next-auth或自定义JWT验证。在layout.tsx中调用auth()获取会话信息。

Q5. Pages Router可以与App Router共存吗? 可以。app/pages/目录可以在同一项目中共存,方便逐步迁移。但建议新项目完全使用App Router。

Q6. 如何优化App Router应用的Core Web Vitals 使用next/imagepriority属性优化LCP;利用Suspense边界减少CLS;通过服务器组件减少JS bundle体积改善INP;使用next/font消除字体加载导致的布局偏移。

🔧 Related Free Tools

相关