Next.js 是啥

在以前,我們要架網站

還需要用

做後端

FastAPI

需要用

做前端

React

而中間通訊要用

RESTful API

JSON

HTML Form、Query String

HTML

GraphQL

十分的麻煩

Next.js 就是為了解決這個問題而生的 全端框架

// frontend/UserProfile.jsx
function UserProfile({ userId }) {
  const [user, setUser] = useState(null)

  useEffect(() => {
    fetch(`http://localhost:8000/api/user/${userId}`)
      .then(res => res.json())
      .then(setUser)
  }, [userId])

  return user ? <p>{user.name}</p> : <p>Loading...</p>
}

傳統方法

十分麻煩

Next.js

// app/user/[id]/page.jsx

async function UserProfile({ params }) {
  const user = await db.getUser(params.id)  // 直接呼叫 DB,不經過 HTTP
  return <p>{user.name}</p>
}

簡單快速

Component

Component

Next.js 的核心是 React Component

因此,只要學過 React,就能輕鬆學會 Next.js

但他和一般的 React 有些不同,有兩種種類的 Component

Client Component

  • 伺服器端渲染(SSR
  • 動態(會載入 JS)
  • 可以:
    • useState / useEffect 
    • 點擊事件監聽
    • 操作 DOM / window
    • 瀏覽器 AP(LocalStorage等)
  • 在第一行加上 "use client" 來啟用
  • 伺服器端渲染(SSR)
  • 靜態(渲染成純 HTML/CSS)
  • 可以:
    • 直接存取資料庫
    • 讀取環境變數
    • 直接 fetch
    • 處理身份驗證
  • 預設就是 

Server Component

那我兩者的功能都想用呢?

 

答案是組合使用,這也是 Next.js 最推薦的架構方式。

核心原則:Server Component 負責資料,Client Component 負責互動。

app/
├── posts/
│   ├── page.jsx          ← Server Component(拉資料)
│   └── components/
│       └── LikeButton.jsx ← Client Component(互動)
app/
├── posts/
│   ├── page.jsx           ← Server Component(拉資料)
│   └── components/
│       └── LikeButton.jsx ← Client Component(互動)
// app/posts/page.jsx  (Server Component)
import LikeButton from "./components/LikeButton";
import { db } from "@/lib/db";


export default async function PostsPage() {
  const post = await db.post.findFirst()
  return (
    <main>
      <h1>Posts</h1>
      <LikeButton post={post} />
    </main>
  );
}
// app/posts/components/LikeButton.jsx  (Client Component)
"use client";

export default function LikeButton({ post }) {
  return (
    <button onClick={() => alert(`你已按讚貼文 ${post}`))}>
      ❤️ 按讚 {post}
    </button>
  );
}

重要限制:資料只能從 Server 網 Client 傳,如果 Client 要用到 Server 的功能,則需要使用 Server Action。

Server

Action

Server Action

告別傳統 API Call 吧

只要在函式內部加上 "use server"
Next.js 就會自動把函式呼叫轉換成 API,並在伺服器執行

這稱作 inline Server Action,但只能在 Server Side Component 使用

// app/posts/new/page.jsx
export default function NewPostPage() {
  async function createPost(formData) {
    "use server"  // 放在函式內部

    const title = formData.get('title')
  
  	// 直接存取資料庫
  	await db.query('INSERT INTO posts (title) VALUES (?)', [title])
    
    revalidatePath('/posts')
  }

  return (
    <form action={createPost}>
      <input name="title" placeholder="標題" />
      <button type="submit">送出</button>
    </form>
  )
}

Server Action

或是拆分成多個檔案也可以!這樣就可以在 Client Side Compoent 裡用了!

// app/posts/new/page.jsx
"use client"

import { useState } from 'react'
import { createPost } from '../../../actions'

export default function NewPostPage() {
  const [title, setTitle] = useState('')

  async function handleClick() {
    await createPost(title)
  }

  return (
    <div>
      <input
        value={title}
        onChange={e => setTitle(e.target.value)}
        placeholder="標題"
      />
      <button onClick={handleClick}>送出</button>
    </div>
  )
}
// app/actions.js
"use server"

import { revalidatePath } from 'next/cache'

export async function createPost(formData) {
  const title = formData.get('title')
  await db.query('INSERT INTO posts (title) VALUES (?)', [title])
  revalidatePath('/posts')
}

檔案路由

檔案路由

在 Next.js 中,資料夾結構即是你的路由網址。不需要額外的設定檔。

app/
├── page.jsx         // 首頁 (/)
├── about/
│   └── page.jsx     // 關於我們 (/about)
└── dashboard/
    ├── settings/
    │   └── page.jsx // 設定頁 (/dashboard/settings)
    └── page.jsx     // 面板頁 (/dashboard)
  • page.jsx:定義該路徑的 UI
  • 資料夾:定義路徑名稱
  • 階層結構:對應網址深淺

動態路由

// app/posts/[id]/page.jsx
export default async function PostPage({ params }) {
  // /posts/123/ → params.id =123
  const post = await db.getPost(params.id)
  return <h1>{post.title}</h1>
}
export default function Page({ params }) {
  // /post/a/b/c → params.slug = ['a', 'b', 'c']
  return <p>{params.slug.join('/')}</p>
}
export default function Page({ params }) {
  // /post       → params.slug = undefined
  // /post/a/b   → params.slug = ['a', 'b']
  return <p>{params.slug?.join('/') ?? '首頁'}</p>
}

使用 [slug] 代表 那一段 可以是任意文字

app/
└── posts/
    └── [id]/
        └── page.jsx  ← /posts/1, /posts/2, /posts/abc
app/
└── post/
    └── [...slug]/
        └── page.jsx   ← /post/a, /post/a/b, /post/a/b/c

使用 [...slug] 代表 多段 可以是任意文字

使用 [[...slug]] 代表 零或多段 可以是任意文字

app/
└── post/
    └── [[...slug]]/
        └── page.jsx   ← /post 也符合(上面的不行)

總結

React SPANext.js
渲染位置瀏覽器伺服器 + 瀏覽器
SEO
載入速度慢(等 JS)快(HTML 直接有內容)
打包方式把整個網站包再一起只打包必要、精簡的內容
後端 API需要另外建內建 API Route / Server Action
路由需要 React Router內建 File-based Routing
適合場景純前端應用高互動後台、Dashboard、內容型網站、電商

總結

React SPA 開發方式Next.js
XHR / Fetch API
(手動發送並解析請求)
Server Component
(直接呼叫函式,不需要管底層原理)
Express / FastAPI 後端
(分兩個專案,需處理 API 格式一致性)
API Route / Server Action
(同一專案,直接呼叫函式,可提供型別檢查)
React Router
(手動設定路由)
File-based Routing
(資料夾結構即路由,清晰易懂)

總結

同場加映

以下是一些有趣的相關內容

過往漏洞

Next.js 是出了名的常出漏洞,以下是一些最近的嚴重漏洞:

  • CVE-2025-66478 (10 分):反序列化錯誤導致遠端程式碼執行
  • CVE-2025-29927 (9.1分):Middleware 權限驗證繞過
  • CVE-2026-44578 (8.6分):內部網路暴露
  • CVE-2026-23864 (7.5分):記憶體/CPU 耗盡 DoS
  • CVE-2025-55183 (5.3分):暴露伺服器端的原始碼

  • 還有很多很多

因此,使用 Next.js 時應定時更新,避免受到漏洞影響。

OpenNext

Next.js 是由 Vercel 開發的,儘管它是開源的,但它的部署系統和 Vercel 的環境高度耦合,因此,我們很難將 Next.js 部署到其他託管服務(如 Cloudflare Worker、Netlify 等)

 

OpenNext 就是為了解決這個問題而生的,旨在使 Next.js 真正實現可移植性——能夠部署在任何平台上,而不僅僅是 Vercel。

為了避免我們被
Vercel 綁架,我很建議大家在專案中使用 OpenNext,讓我們可以隨心所欲的部署我們的 Next.js 網站。

Vinext

Cloudflare 和 Vercel 一直都不太喜歡彼此。

 

有一天 Cloudflare 心血來潮,決定用 AI 把 Next.js 重寫,並和 Vite 結合。於是,經過幾個星期,Vinext 就誕生了。Cloudflare 表示,Vinext 速度更快、更穩定、也更容易部署到各種平台。

 

Vercel 聽到後很生氣,在 X 上罵說這是一個粗糙的 Fork,並指出許多關鍵漏洞。

但這些漏洞讓他感覺就像是一個真正的 Next.js 複製版。

 

但由於他和 Next.js 不完全相容,且全是 AI slop,還只是實驗性專案。

我覺得我們還是聽聽就好,不要真的使用它。