在 Next.js 13.4+ 中,官方正式推出 Server Actions(服务端函数)功能,让你无需编写 API 路由,就能直接在服务端处理表单提交、数据库操作等逻辑。本文通过一个简单的"留言提交"例子,带你快速掌握 Server Actions 的用法、优势和最佳实践。
一、什么是 Server Actions?
Server Actions 是 Next.js 提供的一种新机制,允许你在服务端组件中定义函数 ,并通过客户端(如表单)直接调用它,而无需创建单独的 /api
路由。
核心特点:
- ✅ 函数在服务端执行(安全!)
- ✅ 自动处理 CSRF 保护
- ✅ 支持
async/await
- ✅ 与 React 表单天然集成
- ✅ 自动序列化参数(支持对象、数组等)
💡 它不是替代 API 路由,而是为简单、私有、页面专属的逻辑提供更简洁的方案。
server action的概念其实来自于React的server function,指的是运行在服务器端的函数,通常用于处理业务逻辑、访问数据库、执行权限校验,Server Function 是一个通用术语,泛指任何运行在服务端的函数。
server action是 Server Function 的一种特定用法:专门用于处理表单提交、按钮点击等用户交互触发的异步操作.一个函数如果被标记为 action(比如通过 action={myAction}传递),或者从一个 action函数内部调用,那么它就被称为 Server Action。
二、为什么用 Server Actions? vs 传统 API 路由
场景 | 传统 API 路由 | Server Actions |
---|---|---|
表单提交 | 需写 /api/submit + fetch |
直接调用函数,无需 fetch |
数据验证 | 在 API 文件中处理 | 在函数内直接处理 |
错误反馈 | 需解析 JSON 响应 | 直接抛出错误,自动捕获 |
安全性 | 需手动防 CSRF | 自动内置保护 |
代码量 | 多文件(API + 页面) | 单文件搞定 |
🎯 适用场景:用户注册、评论提交、点赞、设置偏好等页面级操作。
三、实战例子:实现一个"留言提交"功能
我们将创建一个页面,用户输入名字和留言,点击提交后保存到内存(模拟数据库),并刷新列表。
⚠️ 注意:Server Actions 仅在 App Router 中可用。
第一步:启用 Server Actions(Next.js 13.4+ 默认开启)
确保 next.config.js
中启用了(新版默认已开):
js
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true, // Next.js 14+ 可省略
},
};
export default nextConfig;
第二步:创建留言页面
创建文件:app/guestbook/page.js
jsx
// app/guestbook/page.js
'use client';
import { useState, useActionState } from 'react';
import { submitMessage } from './actions';
export default function Guestbook() {
const [name, setName] = useState('');
const [message, setMessage] = useState('');
const [state, formAction] = useActionState(submitMessage, { success: false, error: null });
const handleSubmit = (e) => {
e.preventDefault();
formAction({ name, message });
// 清空表单(可选)
setName('');
setMessage('');
};
return (
<div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
<h1>📝 留言板</h1>
{/* 显示结果 */}
{state?.success && <p style={{ color: 'green' }}>✅ 留言成功!</p>}
{state?.error && <p style={{ color: 'red' }}>{state.error}</p>}
{/* 表单 */}
<form onSubmit={handleSubmit}>
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="你的名字"
required
style={{ display: 'block', margin: '0.5rem 0', padding: '0.5rem' }}
/>
</div>
<div>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="留言内容"
required
rows="3"
style={{ display: 'block', margin: '0.5rem 0', padding: '0.5rem' }}
/>
</div>
<button type="submit" style={{ padding: '0.5rem 1rem', backgroundColor: '#0070f3', color: 'white' }}>
提交留言
</button>
</form>
{/* 模拟显示留言(实际应从数据库读取) */}
<div style={{ marginTop: '2rem' }}>
<h2>已有留言</h2>
<ul>
<li>张三:Next.js 太棒了!</li>
<li>李四:Server Actions 真香!</li>
</ul>
</div>
</div>
);
}
第三步:创建 Server Action(服务端函数)
创建文件:app/guestbook/actions.js
jsx
// app/guestbook/actions.js
'use server';
// 模拟数据库(真实项目用 Prisma、Drizzle 等)
let messages = [];
export async function submitMessage(prevState, formData) {
try {
const { name, message } = formData;
// 简单验证
if (!name || !message) {
return { success: false, error: '名字和留言不能为空!' };
}
// 模拟保存到数据库
messages.push({ name, message, timestamp: new Date() });
console.log('新留言:', { name, message });
// 返回成功状态
return { success: true, error: null };
} catch (error) {
return { success: false, error: '提交失败,请重试。' };
}
}
🔑 关键点:
- 文件顶部必须加
'use server'
;- 函数必须是
async
;- 第一个参数是前一次的状态(用于
useActionState
),第二个是传入的数据。
第四步:运行并测试
bash
npm run dev
访问 http://localhost:3000/guestbook
,填写表单并提交。
你会看到:
- 控制台打印日志(证明在服务端执行)
- 页面显示"✅ 留言成功!"
- 没有网络请求到
/api
!数据直接通过 Server Action 处理
四、Server Actions 最佳实践
1. 只用于私有逻辑
- 不要暴露敏感操作(如删除用户)给公开页面;
- 适合当前用户专属操作(如设置偏好、提交评论)。
2. 配合身份验证
在函数内检查用户登录状态:
js
'use server';
import { auth } from '@/auth';
export async function postComment(formData) {
const session = await auth();
if (!session) throw new Error('未登录');
// ...保存评论
}
3. 错误处理要友好
- 返回结构化状态(如
{ success, error }
); - 避免直接 throw,除非你想中断流程。
4. 不要在客户端组件中定义
Server Action 必须定义在服务端上下文 中(即带 'use server'
的文件),不能写在 'use client'
组件里。
5. 参数自动序列化
支持传对象、数组、Date 等,但不能传函数、Symbol、undefined。
五、常见问题 FAQ
Q1:Server Actions 能替代所有 API 路由吗?
不能。适合页面专属、简单操作;复杂、公共、需 CORS 的接口仍用 API 路由。
六、结语
Server Actions 是 Next.js 向"全栈一体化"迈出的重要一步。它让开发者用更少的代码、更安全的方式处理服务端逻辑,尤其适合表单交互场景。
记住:能用 Server Actions 解决的,就别写 API 路由了!