从0死磕全栈之Next.js Server Actions 入门实战:在服务端安全执行逻辑,告别 API 路由!

在 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 路由了!

相关推荐
β添砖java7 分钟前
vivo响应式官网
前端·css·html·1024程序员节
web打印社区5 小时前
使用React如何静默打印页面:完整的前端打印解决方案
前端·javascript·vue.js·react.js·pdf·1024程序员节
喜欢踢足球的老罗5 小时前
[特殊字符] PM2 入门实战:从 0 到线上托管 React SPA
前端·react.js·前端框架
小光学长5 小时前
基于Vue的课程达成度分析系统t84pzgwk(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
Baklib梅梅6 小时前
探码科技再获“专精特新”认定:Baklib引领AI内容管理新方向
前端·ruby on rails·前端框架·ruby
南方以南_7 小时前
Chrome开发者工具
前端·chrome
YiHanXii7 小时前
this 输出题
前端·javascript·1024程序员节
楊无好7 小时前
React中ref
前端·react.js
程琬清君7 小时前
vue3 confirm倒计时
前端·1024程序员节
歪歪1007 小时前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节