Next.jsServer ActionsFetch表单

Next.js Server Actions 与 Fetch 怎么选

比较表单 Server Action、客户端 fetch 和直接调用后端 API 的边界,说明认证、渐进增强、缓存刷新、文件上传与公开 API 场景下的选择方法。

·更新于 ·阅读约 9 分钟·计算中...
Next.js Server Actions 与 Fetch 怎么选

Server Action 适合由 Next.js 页面发起的服务端变更,尤其是表单提交、权限校验和更新后刷新缓存;客户端 fetch 适合即时搜索、轮询、上传进度和需要显式控制请求生命周期的交互;公开给多个客户端使用的能力仍应设计 Route Handler 或独立后端 API。

目录

三种调用方式

方式 适合场景 主要边界
Server Action Next.js 内部表单和数据变更 不是通用公开 API
Client fetch → Route Handler 高交互客户端请求 需要维护 HTTP 接口
Client fetch → Strapi 等后端 后端本身是公开 API 浏览器可见地址,受 CORS 和公开权限约束

Server Action 表单

// app/actions.ts
"use server"

import { revalidateTag } from "next/cache"

export async function createArticle(formData: FormData) {
  const title = String(formData.get("title") ?? "").trim()

  if (title.length < 3) {
    return { ok: false, message: "标题至少 3 个字符" }
  }

  const user = await requireUser()
  await saveArticle({ title, authorId: user.id })
  revalidateTag("articles")

  return { ok: true }
}
import { createArticle } from "@/app/actions"

export function ArticleForm() {
  return (
    <form action={createArticle}>
      <input name="title" required minLength={3} />
      <button type="submit">创建文章</button>
    </form>
  )
}

表单 Action 可以与 React 的 pending、结果状态能力配合,并保留渐进增强路径。但所有输入仍必须在服务端验证。

客户端 fetch

即时搜索不一定适合 Server Action:

"use client"

import { useEffect, useState } from "react"

export function SearchBox({ query }: { query: string }) {
  const [results, setResults] = useState([])

  useEffect(() => {
    const controller = new AbortController()

    fetch(`/api/search?q=${encodeURIComponent(query)}`, {
      signal: controller.signal,
    })
      .then((response) => {
        if (!response.ok) throw new Error(`Search failed: ${response.status}`)
        return response.json()
      })
      .then(setResults)
      .catch((error) => {
        if (error.name !== "AbortError") console.error(error)
      })

    return () => controller.abort()
  }, [query])

  return <ResultList results={results} />
}

客户端 fetch 可以取消、并发和细粒度处理响应,但要自行处理 loading、错误、竞态与重试。

安全差异

Server Action 在服务器执行,不代表自动安全:

  • 每次调用都验证当前用户身份和资源权限。
  • 不信任隐藏 input、URL 参数和客户端传来的 ID。
  • 对金额、角色和资源归属在服务端重新计算。
  • 添加必要的速率限制和审计日志。
  • 不把异常堆栈和后端响应原样返回用户。

客户端直接请求 Strapi 时,只能使用允许暴露的 Public 权限或用户自己的凭据。私密 Strapi API Token 必须留在 Server Action、Route Handler 或服务端数据层。

缓存刷新

Server Action 的优势之一是变更后可以调用 Next.js 的 revalidation API,让相关页面或 tag 失效。客户端 fetch 也能请求一个完成相同操作的 Route Handler,但需要自己设计协议。

不要在数据库写入失败时提前刷新缓存;也不要只刷新前端状态却忘记服务端缓存,导致刷新页面又看到旧数据。

何时不要使用 Server Action

  • API 需要被移动端、第三方或其他服务调用。
  • 需要标准 REST/Webhook 合约和独立版本管理。
  • 上传需要精确进度、分片或直接传对象存储。
  • 高频实时请求、轮询或搜索建议使用专门接口。
  • 业务后端独立部署,Next.js 只是其中一个客户端。

选择流程

  1. 这是 Next.js 页面里的数据变更吗?优先评估 Server Action。
  2. 需要客户端持续控制请求、取消或显示上传进度吗?使用 fetch。
  3. 多种客户端都要调用吗?设计 Route Handler 或独立 API。
  4. 涉及私密凭据吗?调用必须经过服务端。
  5. 更新后是否影响缓存页面?明确 revalidation 策略。

如果后端是 Strapi,可以继续阅读 Next.js 连接 Strapi 5。组件边界不清楚时参考 Server 与 Client Components

参考资料

订阅 FreeMac

每周精选:免费 Mac 软件评测、可信来源更新、替代方案和少折腾指南。