
在 Next.js 13 的 App Router 中,Server Actions 不支持类似 Express 的 res.send() 响应方式;正确做法是直接 return 序列化数据,客户端通过 await 调用获取结果。
在 next.js 13 的 app router 中,server actions 不支持类似 express 的 `res.send()` 响应方式;正确做法是直接 `return` 序列化数据,客户端通过 `await` 调用获取结果。
Next.js 13 引入的 Server Actions 是一种在服务端执行、无需手动配置 API 路由即可与客户端交互的机制。它并非传统意义上的 HTTP 接口,因此不能访问 req/res 对象,也不支持 res.send()、res.json() 等响应方法。你看到的 res.send({title: "OK"}) 会直接报错(ReferenceError: res is not defined),因为该变量根本不存在于 Server Action 的执行上下文中。
✅ 正确做法是:将操作结果作为普通 JavaScript 值 return 出来。Next.js 会自动序列化返回值(要求为 JSON-safe 类型:字符串、数字、布尔、null、纯对象或数组),并在客户端以 Promise 形式解析。
以下是一个规范实现示例:
// app/actions/create-foo-action.js
'use server';
import { connectDB } from '@utils/database';
import { User } from '@models/user';
export async function createFoo(foo) {
try {
await connectDB();
await User.create(foo);
// ✅ 正确:直接返回结构化数据
return { success: true, title: 'OK', data: { id: '...' } };
} catch (err) {
// ✅ 错误处理也应返回统一格式,便于客户端判断
console.error('Failed to create foo:', err);
return {
success: false,
title: 'Error',
message: err.message || 'Creation failed'
};
}
}在客户端组件中调用时,需确保组件标记为 Client Component(添加 'use client'),并使用 async/await 处理返回值:
// app/components/CreateButton.tsx
'use client';
import { useState } from 'react';
import { createFoo } from '@/app/actions/create-foo-action';
export default function CreateButton() {
const [status, setStatus] = useState(null);
const handleSubmit = async () => {
setStatus('pending');
try {
const result = await createFoo({ name: 'John Doe', email: 'john@example.com' });
setStatus(result); // e.g., { success: true, title: 'OK' }
if (result.success) {
alert('✅ Created successfully!');
}
} catch (error) {
// ⚠️ 注意:Server Action 抛出未捕获异常时,会触发 React Error Boundary;
// 但建议在 action 内部 `catch` 并 `return` 错误对象,更可控
setStatus({ success: false, title: 'Unexpected Error', message: error.message });
}
};
return (
<div>
<button onClick={handleSubmit} disabled={status === 'pending'}>
{status === 'pending' ? 'Creating...' : 'Create User'}
</button>
{status && 'success' in status && (
<p className={`mt-2 text-sm ${status.success ? 'text-green-600' : 'text-red-600'}`}>
{status.title}: {status.message}
</p>
)}
</div>
);
}? 关键注意事项:
- ✅ 必须在函数顶部添加 'use server' 指令,否则不会被识别为 Server Action;
- ✅ 返回值必须是可序列化的(不可含 Date、Map、Set、函数、Promise 或循环引用);
- ✅ 推荐统一返回 { success, title, message?, data? } 结构,提升客户端处理一致性;
- ❌ 不要尝试导入或使用 NextResponse、res、Response 等服务端响应类——它们不适用于 Server Action;
- ⚠️ 若需流式响应、文件上传、自定义状态码或中间件逻辑,仍应使用 Route Handlers(即 /app/api/xxx/route.ts)。
总结:Next.js Server Actions 的设计哲学是「简化数据提交」而非「替代 API 路由」。它让表单提交、按钮点击等常见交互变得零配置、类型安全且服务端直连。只需牢记——不发响应,只返回值;不在服务端渲染逻辑里写 res.send(),而在客户端 await 并消费返回对象——即可高效、稳健地构建数据驱动的应用。










