什麼是 Server Actions

傳統上,在 Next.js 中處理表單提交的流程是:

客戶端表單 → 發送 POST 請求 → API Route 處理 → 回傳結果 → 客戶端更新 UI

Server Actions 讓這個流程簡化為:

客戶端表單 → 直接呼叫伺服器函式 → UI 自動更新

Server Actions 是在伺服器端執行的非同步函式,帶有 use server 指令。你可以直接從 Server Component 的 JSX 中呼叫它,或從 Client Component 的 事件處理器中呼叫。

基本寫法

在 Server Component 中直接定義

在標有 async 的 Server Component 函式中,直接定義帶有 use server 指令的函式:

export default function ContactPage() {

async function handleSubmit(formData: FormData) {

'use server'

const email = formData.get('email') as string

const message = formData.get('message') as string

// 直接呼叫 Prisma 儲存到資料庫,不需要 API Route

await prisma.inquiry.create({ data: { email, message } })

// 讓快取失效,讓相關頁面重新渲染

revalidatePath('/admin/inquiries')

}

return (

<form action={handleSubmit}>

<input name="email" type="email" />

<textarea name="message" />

<button type="submit">送出</button>

</form>

)

}

獨立的 actions.ts 檔案(推薦)

把 Server Actions 集中在一個 actions.ts 檔案中,用 use server 指令標示整個檔案,讓 Client Components 也能 import 使用:

// app/actions.ts

'use server'

import { prisma } from '@/lib/prisma'

import { revalidatePath } from 'next/cache'

export async function createInquiry(formData: FormData) {

const email = formData.get('email') as string

await prisma.inquiry.create({ data: { email } })

revalidatePath('/admin/inquiries')

}

在 Client Component 中使用

Client Component 不能直接定義 Server Actions(因為它在瀏覽器執行),但可以 import 並呼叫來自 actions.ts 的 Server Actions:

'use client'

import { createInquiry } from './actions'

import { useTransition } from 'react'

export function ContactForm() {

const [isPending, startTransition] = useTransition()

function handleSubmit(e: React.FormEvent<HTMLFormElement>) {

e.preventDefault()

const formData = new FormData(e.currentTarget)

startTransition(async () => {

await createInquiry(formData)

})

}

return (

<form onSubmit={handleSubmit}>

<button type="submit" disabled={isPending}>

{isPending ? '送出中...' : '送出'}

</button>

</form>

)

}

useTransition 讓你追蹤 Server Action 是否執行中,用 isPending 顯示載入狀態。

Server Actions 的安全注意事項

Server Actions 在後端執行,調用者是可以偽造的(不一定是你的前端)——任何人都可以用 curl 等工具直接呼叫 Server Actions。

必須驗證:

身份驗證:敏感操作(刪除資料、更新設定)在 Server Action 中一定要先驗證用戶是否登入。用 auth() 或 getSession() 確認用戶身份,未登入就拋出錯誤。

輸入驗證:永遠不要信任 formData 的輸入——用 Zod 等驗證庫驗證格式和內容,再進行資料庫操作。

速率限制:公開表單的 Server Action(如聯絡表單)應考慮加入速率限制(IP 或 session 限制),防止同一個 IP 大量提交。

useFormState 和表單錯誤回傳

Server Actions 可以回傳值,配合 useFormState hook 讓表單顯示伺服器端的驗證錯誤:

在 Server Action 中回傳錯誤訊息,在 Client Component 中用 useFormState 接收並顯示,這樣可以在不需要 try/catch 的情況下優雅地處理表單驗證錯誤。

適合和不適合用 Server Actions 的場景

適合:

  • 表單提交(聯絡表單、登入、留言)
  • 管理後台的 CRUD 操作
  • 業務邏輯觸發(發送 Email、第三方 API 調用)

不適合:

  • 複雜的 RESTful API(需要給外部系統使用)
  • 需要特殊的 HTTP 方法或 Header 回應
  • WebSocket 等即時通訊

對內部使用的操作,Server Actions 比 API Routes 更簡潔;對需要公開的 API,仍然用 App Router 的 route.ts 建立 API Route。