Hiểu sâu về Server Actions và thao tác dữ liệu trong Next.js 14

Đọc trong 3 phút
2026-03-13
2,201
Tôi kiếm được hoa hồng khi bạn mua sắm thông qua các liên kết dưới đây, mà không phát sinh thêm chi phí nào cho bạn.

Tính năng Server Actions trong Next.js 14 đánh dấu một bước tiến quan trọng trong cách thức xử lý dữ liệu ở phía máy chủ. Nó cho phép các nhà phát triển định nghĩa các hàm không đồng bộ trực tiếp bên trong các thành phần server, để xử lý các thao tác như gửi biểu mẫu, thay đổi dữ liệu, v.v., mà không cần phải tạo các route API riêng biệt. Cách tiếp cận này giúp đơn giản hóa dòng dữ liệu, nâng cao hiệu quả phát triển và tăng cường tính bảo mật cho ứng dụng.

Server Actions là gì?

“Server Actions” là một loại hàm trong Next.js được thực thi trên phía máy chủ. Chúng có thể được định nghĩa trực tiếp bên trong các component React và được kích hoạt thông qua các biểu mẫu (forms) hoặc sự kiện (events). Ưu điểm chính của chúng là toàn bộ logic thực thi diễn ra trên phía máy chủ; phía client chỉ đơn giản gửi yêu cầu và nhận phản hồi, từ đó tự nhiên tránh được tình trạng các thông tin nhạy cảm hoặc khóa truy cập bị tiết lộ cho phía client.

Bằng cách thêm nội dung đó ở đầu tệp tin của thành phần (component file). ‘server-only’ Sử dụng bên trong một lệnh hoặc hàm ‘use server’ Các lệnh cho phép đánh dấu một hàm một cách rõ ràng là thao tác xử lý từ phía máy chủ (server-side). Điều này giúp các nhà phát triển có thể viết logic máy chủ một cách trơn tru bên trong các thành phần (components) của ứng dụng, chẳng hạn như thực hiện các giao dịch an toàn trực tiếp với cơ s

Đọc thêm Phân tích toàn bộ quy trình xây dựng website: Thực hành kỹ thuật và điểm cốt lõi từ lập kế hoạch đến triển khai

Một cấu trúc Server Action điển hình hoạt động trực tiếp trong bối cảnh máy chủ và có thể truy cập tất cả các tài nguyên phía máy chủ.

Trợ lý xây dựng trang web WordPress.com
Trợ lý xây dựng trang web WordPress.com
99.9991% Thời gian hoạt động + Khả năng chịu lỗi đa vùng, hỗ trợ 24/7, mua gói blog được miễn phí sử dụng AI xây dựng website
Miễn phí tên miền trong một năm
Truy cập Trợ lý Xây dựng Website WordPress.com →
Trợ lý Xây dựng Website UltaHost
Trợ lý Xây dựng Website UltaHost
900+ mẫu miễn phí, tùy chỉnh được, có được khả năng SEO cần thiết để tối ưu hóa khả năng hiển thị tìm kiếm của website
// 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‘);
}

Triết lý thiết kế và nguyên lý hoạt động

Triết lý thiết kế của Server Actions là “đưa logic của máy chủ trở lại gần các thành phần (components) hơn”. Trong các ứng dụng Next.js truyền thống, việc thay đổi dữ liệu thường đòi hỏi phải định nghĩa trước một thành phần chuyên biệt nằm ở phía máy chủ. pages/api/ Các đường dẫn API nằm trong thư mục đó, sau đó được sử dụng trong các thành phần khách hàng (client components). fetch Khởi tạo yêu cầu (initiating a request). Sự tách biệt này làm tăng độ phức tạp của kiến trúc hệ thống (this separation increases the complexity of the system architecture).

Server Actions được triển khai thông qua việc áp dụng các công cụ và phương thức nhất định. ‘use server’ Lệnh này yêu cầu Next.js đánh dấu các hàm này là chỉ có thể được thực thi trên phía máy chủ trong quá trình biên dịch. Khi khách hàng gọi các hàm này, Next.js sẽ đại diện cho yêu cầu thông qua một điểm cuối (endpoint) RPC (Remote Procedure Call) an toàn và được tạo tự động, gửi các tham số đã được mã hóa (serialized) đến máy chủ để thực thi hàm. Sau khi hàm được thực thi xong, kết quả sẽ được mã hóa lại và trả về cho khách hàng. Toàn bộ quá trình này diễn ra một cách ẩn danh đối với nhà phát triển, tạo cảm giác giống như việc họ đang gọi trực tiếp một hàm nội bộ trên máy tính của mình.

Làm thế nào để định nghĩa và sử dụng Server Actions?

Có hai cách chính để định nghĩa và sử dụng Server Actions: định nghĩa nội tuyến (inline definition) và định nghĩa theo mô-đun (modular definition). Mỗi cách phù hợp với những tình huống khác nhau, nhưng điểm chung là cả hai đều yêu cầu sử dụng các công cụ hoặc quy trình nhất định để triển khai chú ‘use server’ Các lệnh cần được định nghĩa rõ ràng để xác định môi trường thực thi của chúng.

Cách định nghĩa nội tuyến (Inline Definition Method)

Bạn có thể thực hiện điều đó ngay bên trong thành phần máy chủ, bằng cách đặt nó ngay ở đầu thân hàm. ‘use server’ Đây là hướng dẫn để tạo một “Server Action” được đặt ngay trong mã nguồn (inline). Phương pháp này thích hợp cho những thao tác có logic đơn giản và ít khả năng được tái sử dụng, giúp giữ cho mã nguồn liên quan được tổ chức một cách gọn gàng và dễ quản lý.

Đọc thêm Hướng dẫn toàn bộ quy trình xây dựng website hiện đại: Phân tích thực hành hoàn chỉnh từ con số 0 đến 1 và công nghệ cốt lõi

// 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>
  );
}

Cần lưu ý rằng, để đạt được mức độ bảo mật kiểu dữ liệu (type safety) tốt nhất và hiệu quả tối ưu trong quá trình xử lý dữ liệu (Tree-shaking), Next.js khuyến nghị sử dụng phương pháp định nghĩa dữ liệu theo dạng module.

Cách định nghĩa theo nguyên tắc mô-đun hóa (Modular Definition Method)

Đối với những logic phức tạp hơn hoặc cần được sử dụng nhiều lần, khuyến nghị nên định nghĩa các Server Action trong các tệp module riêng biệt. Ví dụ: app/actions/ Nó nằm trong thư mục. Điều này giúp duy trì tính mô-đun hóa và khả năng bảo trì của mã nguồn, đồng thời thuận tiện cho việc thực hiện các bài kiểm thử đơn vị (unit tests).

Trước hết, hãy định nghĩa và xuất các hành động (actions) của bạn vào một tệp riêng biệt:

Trợ lý xây dựng trang web Bluehost
Cung cấp công cụ tạo website AI, hỗ trợ trò chuyện trực tuyến và điện thoại 24/7, tên miền miễn phí một năm, CDN miễn phí, thời gian hoạt động SLA 99.99%
// 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: ‘用户创建成功!‘ };
}

Sau đó, hãy nhập và sử dụng nó trong các thành phần khách hàng (client-side) hoặc thành phần máy chủ (server-side). Trong các thành phần khách hàng, bạn cần phải kết hợp nó với React. useActionState Hãy sử dụng các Hook để quản lý trạng thái.

// 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="/vi/formAction/" data-trp-original-action="{formAction}">
      <div>
        <label htmlfor="name">Tên</label>
        <input id="name" name="name" />
        {state?.errors?.name && <span>{state.errors.name}</span>}
      </div>
      <div>
        <label htmlfor="email">Email</label>
        <input id="email" name="email" type="email" />
        {state?.errors?.email && <span>{state.errors.email}</span>}
      </div>
      <button type="submit" disabled="{isPending}">
        {isPending ? ‘Đang được tạo…‘ : ‘Tạo người dùng…‘}
      </button>
      {state?.message && <p>{state.message}</p>}
    <input type="hidden" name="trp-form-language" value="vi"/></form>
  );
}

Những ưu điểm cốt lõi và cách thực hiện của Server Actions

Việc đưa vào các chức năng liên quan đến “Server Actions” (Các Thao tác Trên Máy chủ) đã giải quyết được nhiều vấn đề quan trọng trong quá trình phát triển ứng dụng theo mô hình full-stack, từ khía cạnh bảo mật cho đến trải nghiệm phát triển, đều có những cải thiện đáng kể.

Sơ đồ dữ liệu được đơn giản hóa và tính bảo mật dữ liệu theo nguyên tắc từ đầu đến cuối (end-to-end type safety)

Truyền thống, “API route +” fetch”Các mô hình này hỗ trợ việc chuyển đổi ngữ cảnh (context switching) và đặt điểm dừng kiểm tra kiểu dữ liệu (type breakpoints). Server Actions cho phép bạn coi các hàm trên máy chủ như những module có thể được nhập vào chương trình, và khi kết hợp với TypeScript, bạn có thể đảm bảo tính an toàn về kiểu dữ liệu (type safety) từ cấp độ cấu trúc dữ liệu trong cơ sở dữ liệu (database schema) đến các biểu mẫu trên phía người dùng (frontend forms). Bạn có thể định nghĩa các tham số đầu vào dưới dạng Zod hoặc các định dạng tương tự Schema trong các hàm server action, và điều này giúp bạn nhận được những thông báo về kiểu dữ liệu chính xác cũng như các quy trình kiểm tra trên phía client, từ đó giảm đáng kể số lượng lỗi xảy ra trong quá trình chạy chương trình.

Đọc thêm Tại sao chọn Tailwind CSS: Giải thích chi tiết những lợi thế cốt lõi và thực tiễn tốt nhất

An ninh được nâng cao và các biện pháp bảo vệ được tích hợp sẵn trong hệ thống.

Các thao tác trên máy chủ (server actions) được bảo vệ bởi một loạt biện pháp an ninh mặc định. Next.js tự động áp dụng các biện pháp bảo mật này cho tất cả các trường hợp sử dụng. POST Phương thức Server Actions thực hiện bảo vệ chống lại tấn công xác thực người dùng giả mạo qua trang web khác (Cross-Site Request Forgery – CSRF) bằng cách kiểm tra các yêu cầu được gửi đến. OriginHost Đầu tiên, cần kiểm tra nguồn gốc của yêu cầu để đảm bảo tính bảo mật. Quan trọng hơn nữa, vì các logic nghiệp vụ (như truy vấn cơ sở dữ liệu, gọi dịch vụ bên thứ ba) được thực hiện trên máy chủ, nên các biến môi trường nhạy cảm và khóa API sẽ không bao giờ bị lộ ra trong gói phần mềm được gửi đến phía máy khách.

Một cơ chế xác thực lại bộ đệm hiệu quả

Server Actions được tích hợp sâu rộng với hệ thống đệm (cache) của Next.js. Sau khi dữ liệu thay đổi, bạn có thể sử dụng các chức năng liên quan đến Server Actions để xử lý những thay đổi đó một cách hiệu quả. revalidatePathrevalidateTag Hàm này được thiết kế để làm cho dữ liệu được lưu trữ trong bộ đệm (cache) tại một đường dẫn cụ thể hoặc có những thẻ (tags) nhất định trở nên không còn hợp lệ (không còn được sử dụng nữa). Điều này có nghĩa là sau khi thực hiện thao tác tạo một bài viết trên blog, bạn có thể ngay lập tức làm mới dữ liệu trong trang danh sách các bài viết, đảm bảo người dùng nhìn thấy thông tin mới nhất mà không cần phải chờ đợi quá trình tạo lại nội dung tĩnh theo từng phần (incremental static re

hosting.com
SSL miễn phí, CDN Cloudflare, WAF, hơn 40 trung tâm dữ liệu toàn cầu để lựa chọn, độ trễ thấp hơn nhờ vị trí gần, hỗ trợ dịch vụ 24/7/365, hiện có thể tiết kiệm tới 67% chi phí, hỗ trợ xây dựng AI và tối ưu hóa 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‘);
}

Tăng cường dần dần và tối ưu hóa trải nghiệm người dùng

Ngay cả khi việc tải JavaScript từ phía client thất bại hoặc bị vô hiệu hóa hoàn toàn, ứng dụng vẫn có thể hoạt động bình thường. action Các biểu mẫu HTML mà thuộc tính của chúng trỏ đến Server Action vẫn có thể hoạt động bình thường, điều này đáp ứng được yêu cầu cơ bản của việc nâng cấp dần dần (progressive enhancement). Đối với các trình duyệt hiện đại, bạn có thể tận dụng điều này để tối ưu hóa trải nghiệm người dùng. useFormStatususeOptimistic Chúng ta cần đợi các Hook của React xuất hiện để mang lại trải nghiệm người dùng tốt hơn; ví dụ như hiển thị trạng thái tải dữ liệu khi đang chờ phản hồi từ máy chủ, hoặc thực hiện các thao tác cập nhật dữ liệu một cách nhanh chóng (tức là “tích cực”).

‘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 &amp;&amp; ‘(Đang được gửi…)‘}</div>
      ))}
      <form action="/vi/formAction/" data-trp-original-action="{formAction}">...<input type="hidden" name="trp-form-language" value="vi"/></form>
    </>
  );
}

Tóm lại

Server Actions trong Next.js 14 là một tính năng mang tính đột phá; nó giúp tích hợp logic máy chủ một cách chặt chẽ và rõ ràng hơn vào các thành phần giao diện người dùng (UI components), từ đó đơn giản hóa đáng kể độ phức tạp trong quá trình phát triển ứng dụng toàn diện (full-stack). Đây không chỉ là một giải pháp thay thế cho các luồng API thông thường, mà còn đại diện cho một phương thức xử lý dữ liệu an toàn hơn, hiệu quả hơn và thân thiện hơn với các nhà phát triển. Nhờ cung cấp các luồng dữ liệu được tối ưu hóa, các giá trị mặc định bảo mật mạnh mẽ, khả năng kiểm soát bộ nhớ đệm chính xác, và hỗ trợ tốt cho việc nâng cấp dần dần ứng dụng, Server Actions đã nâng cao đáng kể trải nghiệm và chất lượng khi xây dựng các ứng dụng web hiện đại. Việc nắm vững và áp dụng tốt tính năng này là yếu tố then chốt để tạo ra những ứng dụng Next.js thế hệ tiếp theo với hiệu suất cao và khả năng bảo trì tốt.

FAQ 常见问题

Có thể định nghĩa trực tiếp Server Action trong các thành phần khách hàng (client components) không?

Không được.‘use server’ Lệnh này chỉ có thể được sử dụng trong các mô-đun chạy trên môi trường máy chủ. Ở những nơi được đánh dấu là… ‘use client’ Việc định nghĩa trực tiếp các hành động máy chủ (Server Actions) trong tệp component của phía khách hàng (client-side) sẽ gây ra lỗi khi xây dựng ứng dụng. Cách thực hiện đúng là định nghĩa các hành động máy chủ trong một tệp module riêng biệt hoặc trong component của phía máy chủ, sau đó nhập chúng vào component của phía khách hàng và gọi chúng từ đó.

Liệu “Server Actions” có chỉ giới hạn ở việc xử lý dữ liệu từ các biểu mẫu (form data) không?

Không phải vậy. Mặc dù việc gửi đi đơn (form submission) là trường hợp sử dụng phổ biến nhất của Server Actions (thông qua…) FormData đối tượng), nhưng chúng có thể chấp nhận bất kỳ tham số có thể tuần tự hóa nào, bao gồm chuỗi, số, giá trị boolean, mảng và đối tượng thông thường. Bạn có thể gọi chúng giống như gọi một hàm bất đồng bộ thông thường và truyền các tham số cần thiết.

Làm thế nào để xử lý các lỗi xảy ra trong quá trình thực thi Server Actions?

Bạn nên sử dụng nó bên trong hàm Server Action. try...catch Các khối (blocks) được sử dụng để bắt lỗi và xử lý chúng. Sau đó, thông tin lỗi có thể được truyền về phía client thông qua việc trả về một đối tượng chứa dữ liệu lỗi. Tại phía client, thông tin này có thể được sử dụng để xử lý tình huống phát sinh. useActionState Bạn sử dụng trạng thái được trả về bởi hàm `Hook` để hiển thị thông báo lỗi. Hãy đảm bảo rằng bạn không trả về trực tiếp thông tin chi tiết về lỗi từ phía máy chủ (stack trace) cho phía máy khách, mà thay vào đó hãy hiển thị những thông báo lỗi thân thiện với người dùng.

Việc sử dụng Server Actions có ảnh hưởng đến hiệu năng của ứng dụng của tôi không?

Khi được sử dụng đúng cách, Server Actions thường giúp cải thiện trải nghiệm người dùng về mặt hiệu suất. Chúng giúp giảm kích thước của các gói JavaScript trên phía máy khách, vì các logic được thực thi trên máy chủ. Điều này đặc biệt hữu ích trong trường hợp bạn muốn tối ưu hóa tốc độ phản hồi của ứng dụng. revalidatePathrevalidateTag Việc gọi các hàm (function calls) có thể giúp tránh việc tải lại toàn bộ trang web một cách không cần thiết. Tuy nhiên, cần lưu ý đến hiệu suất thực thi của các hàm đó, để tránh tình trạng các thao tác đồng bộ (synchronous operations) kéo dài làm chặn quá trình xử lý yêu cầu (request processing). Đối với những tác vụ tốn nhiều thời gian, nên xem xét sử dụng các hàng đợi xử lý đồng bộ (async queues) để thực hiện chúng. Ngoài ra, việc gọi quá nhiều lần các hàm Server Action nhỏ có thể làm tăng lượng lưu lượng dữ liệu trên mạng; lúc này cần đánh giá xem liệu việc quản lý trạng thái từ phía client có phù hợp