深入理解 Next.js 14 中的服务器端操作和数据操作

3 分钟阅读时间
2026-03-13
2,221
當您透過下方連結購物時,我會獲得佣金,而您無需支付額外费用。.

Next.js 14 的 Server Actions 功能标志着服务端数据操作模式的重大演进。它允许开发者直接在服务器组件中定义异步函数,用于处理表单提交、数据变更等操作,而无需创建独立的 API 路由。这种模式极大地简化了数据流,提高了开发效率,并增强了应用程序的安全性。

什麼是 Server Actions?

服务器端动作(Server Actions)是 Next.js 中一种在服务器端执行的函数。它们可以直接在 React 组件中定义,并通过表单或事件触发。其核心优势在于,执行逻辑完全在服务器端进行,客户端仅负责发送请求和接收响应,从而自然地避免了敏感逻辑和访问密钥暴露给客户端。

通過在組件文件頂部添加 ‘server-only’ 指令或函數內部使用 ‘use server’ 通过指令,可以明确地将函数标记为服务端操作。这使得开发者能够在组件中无缝地编写服务器逻辑,例如直接与数据库进行安全交互。

推荐阅读 网站建设全流程解析:从规划到上线,全过程技术实践与核心要点

一個典型的 Server Action 結構如下,它直接在服務器上下文中運行,並可以訪問所有服務端資源。

WordPress.com 网站搭建助手
WordPress.com 网站搭建助手
99.999%的高可用性及跨区域容灾功能,全天24小时提供技术支持,购买博客套餐即可免费使用AI建站服务。
免费域名使用期限为一年。
访问 WordPress.com 网站创建助手 →
UltaHost 网站建设助手
UltaHost 网站建设助手
拥有900多个免费、可定制的模板,助您获得优化网站搜索曝光所需的SEO能力。
// app/actions/todo.ts
‘use server‘;

import { revalidatePath } from ‘next/cache‘;
import { db } from ‘@/lib/database‘;

export async function createTodo(formData: FormData) {
  const title = formData.get(‘title‘) as string;
  // 在服务器端安全地执行数据库操作
  await db.todo.create({ data: { title, completed: false } });
  // 操作成功后,使特定路径的缓存失效以更新数据
  revalidatePath(‘/dashboard‘);
}

設計哲學與工作原理

服务器端操作的设计理念是“将服务器逻辑带回组件身边”。在传统的 Next.js 应用中,数据变更通常需要先定义一个位于服务器端的处理程序,然后再将数据传送到客户端。 pages/api/ 目錄下的 API 路由,然後在客戶端組件中使用 fetch 發起請求。這種分離增加了架構的複雜性。

服务器操作通过引入新的功能来增强用户体验,例如数据验证、数据传输和数据处理等。 ‘use server’ 指令,在編譯時將這些函數標記爲僅能在服務器端執行。當客戶端調用這些函數時,Next.js 會通過一個安全的、自動生成的 RPC(遠程過程調用)端點來代理請求,將序列化的參數發送到服務器,執行函數,再將結果序列化後返回給客戶端。整個過程對開發者透明,感覺就像直接調用了一個本地函數。

如何定義與使用 Server Actions

定義和使用 Server Actions 主要有兩種方式:內聯定義與模塊化定義。每種方式適用於不同的場景,共同點是需要使用 ‘use server’ 指令來明確其執行環境。

內聯定義方式

你可以在服務器組件內部,直接在函數體頂部使用 ‘use server’ 指令來創建內聯的 Server Action。這種方式適合邏輯簡單且複用性不高的操作,有助於保持相關代碼的集中性。

推荐阅读 網站建設全流程指南:從零到一的完整實踐與核心技術解析

// app/page.tsx (一个服务器组件)
export default function ServerPage() {
  async function handleLogin(formData: FormData) {
    ‘use server‘;
    const email = formData.get(‘email‘);
    const password = formData.get(‘password‘);
    // 在此处进行身份验证逻辑
    // ...
  }

return (
    <form action={handleLogin}>
      <input type="email" name="email" />
      <input type="password" name="password" />
      <button type="submit">登录</button>
    </form>
  );
}

需要注意的是,爲了獲得最佳的類型安全性與 Tree-shaking 優化,Next.js 官方更推薦使用模塊化定義方式。

模塊化定義方式

针对更复杂或需要多次复用的逻辑,建议将服务器操作定义在单独的模块文件中,例如: app/actions/ 目錄下。這有助於保持代碼的模塊化和可維護性,並便於進行單元測試。

首先,在獨立文件中定義並導出你的動作:

蓝色主机(Bluehost)建站助手
提供人工智能网站创建工具、24/7在线聊天和电话支持、一年免费域名、免费CDN,以及99.991%的正常运行时间服务水平协议(SLA)。
// app/actions/user.ts
‘use server‘;

import { z } from ‘zod‘;
import { db } from ‘@/lib/db‘;
import { revalidateTag } from ‘next/cache‘;

const UserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

export async function createUser(prevState: any, formData: FormData) {
  const validatedFields = UserSchema.safeParse({
    name: formData.get(‘name‘),
    email: formData.get(‘email‘),
  });

if (!validatedFields.success) {
    return {
      errors: validatedFields.error.flatten().fieldErrors,
    };
  }

await db.user.create({ data: validatedFields.data });
  revalidateTag(‘user-list‘); // 使用标签重新验证缓存
  return { message: ‘用户创建成功!‘ };
}

然後,在客戶端或服務器組件中導入並使用。在客戶端組件中,需要配合 React 的 useActionState 等 Hook 來管理狀態。

// app/components/CreateUserForm.tsx
‘use client‘;

import { createUser } from ‘@/app/actions/user‘;
import { useActionState } from ‘react‘;

export function CreateUserForm() {
  const [state, formAction, isPending] = useActionState(createUser, null);

return (
    <form action="/zh-hant/formAction/" data-trp-original-action="{formAction}">
      <div>
        <label htmlfor="name">姓名</label>
        <input id="name" name="name" />
        若有错误,则显示错误名称。若无错误,则显示用户名。 <span>{state.errors.name}</span>}
      </div>
      <div>
        <label htmlfor="email">邮箱</label>
        <input id="email" name="email" type="email" />
        若用户未正确填写电子邮箱,提示框将显示错误信息。具体来说,当用户未正确填写电子邮箱时,提示框会显示错误消息,并在用户点击按钮后关闭。 <span>您的电子邮箱格式有误。请确保电子邮箱的格式正确,例如,用户名@域名.com。</span>}
      </div>
      <button type="submit" disabled="{isPending}">
        {isPending ? ‘创建中...‘ : ‘创建用户‘}
      </button>
      若有状态信息,则显示状态消息,否则显示默认提示文本。 <p>{state.message}</p>}
    <input type="hidden" name="trp-form-language" value="zh-hant"/></form>
  );
}

服务器端操作的核心优势及其实际应用

服务器端操作(Server Actions)的引入解决了全栈应用开发中的多个关键痛点,无论是从安全性还是开发体验方面,都得到了显著提升。

簡化的數據流與端到端類型安全

傳統的“API 路由 + fetch”这种模式存在上下文切换和类型断点。服务器端操作(Server Actions)允许你将服务器函数作为模块导入。结合 TypeScript,你可以实现从数据库模式到前端表单的端到端类型安全。你可以在操作函数中定义输入参数的 Zod 或类似模式,并在客户端获得精确的类型提示和验证,从而大大减少运行时错误。

推荐阅读 为何选择 Tailwind CSS:深度解析其核心优势与最佳实践

增強的安全性與內置防護

服务器端操作默认受一系列安全保护措施的保护。Next.js 会自动为所有使用该框架的应用程序添加这些保护措施。 POST 方法的 Server Actions 實施跨站請求僞造(CSRF)防護,通過檢查 Origin 以及 Host 頭來驗證請求來源。更重要的是,由於業務邏輯(如數據庫查詢、第三方服務調用)在服務器執行,敏感的環境變量和 API 密鑰永遠不會泄露到客戶端捆綁包中。

高效的緩存再驗證機制

服务器端操作与 Next.js 的缓存系统深度集成。在数据发生变化后,您可以使用 revalidatePath 或者 revalidateTag 函數,精確地使特定路徑或帶有特定標籤的緩存數據失效。這意味着,在完成一個創建博客文章的動作後,你可以立即刷新文章列表頁面的緩存,確保用戶看到最新數據,而無需等待增量靜態再生成(ISR)的週期。

hosting.com
免费的 SSL 证书、Cloudflare CDN、WAF 防护,可选择 40 多个全球服务器节点,实现就近连接,降低延迟。提供全年无休的 24/7/365 服务支持。目前可节省高达 671 TB/月的费用,并支持人工智能网站建设和搜索引擎优化(SEO)优化。
‘use server‘;
import { revalidatePath, revalidateTag } from ‘next/cache‘;

export async function updatePost(id: string, content: string) {
  await db.post.update({ where: { id }, data: { content } });
  // 方式一:重新验证特定路径
  revalidatePath(`/posts/${id}`);
  // 方式二:重新验证所有带有该标签的缓存数据
  revalidateTag(‘posts‘);
}

漸進式增強與用戶體驗優化

即使客戶端 JavaScript 加載失敗或完全被禁用,使用 action 屬性指向 Server Action 的 HTML 表單仍然可以正常工作,這實現了漸進式增強的基本要求。對於現代瀏覽器,你可以利用 useFormStatususeOptimistic 等 React Hook 能提供出色的用户体验时,比如在等待服务器响应时显示加载状态,或进行乐观更新等。

‘use client‘;
import { experimental_useOptimistic as useOptimistic } from ‘react‘;
import { sendMessage } from ‘./actions‘;

function Thread({ messages }) {
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) =&gt; [...state, { text: newMessage, sending: true }]
  );

async function formAction(formData) {
    const message = formData.get(‘message‘);
    addOptimisticMessage(message); // 立即樂觀更新UI
    await sendMessage(message); // 調用 Server Action
  }

return (
    <>
      {optimisticMessages.map((msg, idx) =&gt; (
        <div key="{idx}">{msg.text} {msg.sending && ‘(发送中…)‘}</div>
      ))}
      <form action="/zh-hant/formAction/" data-trp-original-action="{formAction}">...<input type="hidden" name="trp-form-language" value="zh-hant"/></form>
    </>
  );
}

总结

Next.js 14 的服务器端操作(Server Actions)是一项革命性的特性,它通过将服务器逻辑更紧密、更声明式地集成到 UI 组件中,极大地简化了全栈开发的复杂性。它不仅仅是一种替代 API 路由的技术方案,更代表了一种更安全、更高效、对开发者更友好的数据操作范式。通过提供简化的数据流、强大的安全默认值、精细的缓存控制以及对渐进式增强的支持,服务器端操作极大地提升了构建现代 Web 应用的体验和质量。掌握并正确应用这一特性,是构建下一代高性能、高可维护性 Next.js 应用的关键。

常见问题解答(FAQ)

在客戶端組件中能否直接定義 Server Action?

不可以。‘use server’ 指令只能在服務器環境下的模塊中使用。在標記爲 ‘use client’ 的客戶端組件文件中直接定義 Server Action 會導致構建錯誤。正確的做法是將 Server Actions 定義在獨立的模塊文件或服務器組件中,然後在客戶端組件中導入並調用它們。

服务器端操作是否仅限于处理表单数据?

不是。雖然表單提交是 Server Actions 最常見的用例(通過 FormData 對象),但它們可以接受任何可序列化的參數,包括字符串、數字、布爾值、數組和普通對象。你可以像調用普通異步函數一樣調用它們,並傳遞所需的參數。

如何處理 Server Actions 執行中的錯誤?

你應該在 Server Action 函數內部使用 try...catch 塊進行錯誤捕獲和處理。然後,可以通過返回一個包含錯誤信息的對象來通知客戶端。在客戶端,可以利用 useActionState 钩子返回的状态用于渲染错误信息。请确保不要将敏感的服务端错误栈直接返回给客户端,而是应返回用户友好的错误消息。

使用 Server Actions 會影響我的應用性能嗎?

正確使用時,Server Actions 通常有助於提升性能感知。它們減少了客戶端 JavaScript 包的大小,因爲邏輯在服務器執行。通過精確的 revalidatePath 或者 revalidateTag 調用,可以避免不必要的全頁面重載。然而,需要注意動作函數的執行效率,避免長時間運行的同步操作阻塞請求。對於耗時任務,應考慮採用異步隊列處理。另外,頻繁調用的小型 Server Action 可能會增加網絡往返,此時需要衡量是否適合採用客戶端狀態管理。