有一种代码是每个团队最终都会毫无疑问地编写的:表单和数据库之间的粘合层。接收 0、验证正文、调用服务、返回 JSON 的端点。另一方面,客户端上的1组装该主体、处理错误、更新状态。将其乘以每个产品写入操作,您就会有数百行的存在,只是为了将数据从一侧移动到另一侧。
Next.js 中的服务器操作正是针对这种粘合剂。该提案很简单:从在服务器上运行的函数执行突变(写入、更新、删除),直接从组件调用,而无需为此设计、版本和维护专用的 [REST API2]。端点仍然存在,但框架会为您生成并连接它。
实践中有哪些变化
服务器操作是标记为在服务器上运行的异步函数。您将它与表单或事件关联起来,[Next.js3 ] 负责传输:序列化参数、进行网络调用、返回结果。从编写屏幕的人的角度来看,看起来您只是在调用本地函数。
与之前的模型相比,差异在于代码更少,同步点更少。不再需要 API 合约来保持两端之间的一致性,也不再需要需要匹配客户端发送的内容的请求模式。记录请求的函数和触发此记录的屏幕彼此接近,并且两端的返回类型相同。
这很重要,因为产品团队中的大多数摩擦并不在于业务逻辑,而在于粘合剂。以前需要路由文件、处理程序、获取客户端和共享类型的每个突变现在都适合一个函数。犯错误的表面更少,出现故障时打开的文件更少。
生产率的提高是真实的,但这不是中心点
将服务器操作作为提高生产力的捷径进行销售是很诱人的,而且确实如此。但将话语简化为“更少的样板文件”低估了正在发生的事情。最重要的收获是架构:敏感逻辑不再通过客户端。
当变异在服务器上运行时,API密钥、银行凭证、价格规则、佣金计算,这些都不需要发送到浏览器。客户端触发意图(“创建此请求”),服务器决定这意味着什么。重要的代码永远不会离开您控制的环境。
这解决了传统 SPA 模型中常见的一类泄漏问题。团队将业务逻辑分散在前端,因为这是最方便的地方,然后发现折扣规则或限制验证在捆绑包中公开。默认情况下,通过服务器上的突变,诱惑就会消失:客户端没有地方可以放置此逻辑,因为客户端只知道调用。
要理解为什么服务器成为这种逻辑的自然场所,值得重新审视 web4 上服务器优先架构的更广泛的思想,其中服务器操作是其中的一部分。
任何人都不能忽视的警告:将进入视为敌对
以下部分将那些善于使用服务器操作的人与那些创建巧妙安全漏洞的人区分开来。服务器操作是公共端点。事实上,您仅从自己的应用程序中的漂亮表单调用它并不会改变这一点。
当 [Next.js5 生成操作时,它会公开接受调用的路由。任何拥有正确工具的人都可以以任何他们想要的参数、任何他们想要的顺序来伪造一个请求。您设计的接口不是障碍:它只是调用该函数的方法之一。认为“但我的前端永远不会发送该值”是典型的错误,因为攻击者没有使用他的前端。
这导致了两项不可协商的义务。首先是验证。在触及任何业务规则之前,需要使用显式模式在服务器上检查到达的每个参数。类型、格式、值范围、字段的存在。 [TypeScript6 的输入在开发过程中有所帮助,但在运行时就消失了;它不会验证从外部调用该路由的人的任何内容。
第二个是授权,它与验证不同。验证回答“这个数据有意义吗?”。授权回复“这个人可以这样做吗?”。每个更改状态的服务器操作都需要在其内部检查用户是谁以及他或她是否有权对该资源执行该操作。不要依赖于在界面中隐藏按钮。隐藏按钮不保护功能;仅检查其内部即可保护。
为什么这些检查需要存在于操作中
人们倾向于将授权集中在中间件中并认为问题已经解决。中间件会有所帮助,但它通常在路由级别运行,而不是在资源级别运行。它可以说“该用户已登录”,但很少可以说“该用户恰好拥有他试图取消的订单”。
这种差异就是最昂贵的失败所在。经过身份验证的合法用户可以尝试仅通过更改调用参数中的标识符来对不属于他们的资源进行操作。 【认证7通过;对特定对象的授权失败。这就是为什么权限检查属于操作主体,靠近业务规则,您可以在其中了解正在更改的内容以及为谁更改的完整上下文。
这个原则很古老,值得更广泛地阅读[Web 应用程序安全的基础知识]8:用户要求的内容和系统执行的操作之间的每个边界都是检查点。服务器操作不会创建此边界,它们使其更加谨慎,而谨慎正是忘记保护的内容。
如何在不搞乱的情况下考虑采用
服务器操作并不能消除对服务层的需求。如果将所有业务逻辑放入操作中,您将重新创建胖控制器问题,只是名称不同。该操作必须是精简的:它接收调用、验证它、授权它并将其委托给一个对 HTTP 或 [Next.js9´一无所知的域函数。
这种分离使逻辑保持可测试和可重用。相同的创建顺序规则可以由操作、队列作业和导入脚本调用,只要它位于操作之外。将服务器操作视为前门,而不是整个房间。
当传统 API 仍然有意义时,也值得诚实地对待。如果您有外部客户、本机移动应用程序或第三方集成,则版本化且记录在案的 API 仍然是正确的答案。服务器操作在您的前端和后端之间的耦合中发挥作用;它们并不是被设计为合作伙伴将使用的公共合同。 [Next.js10? App Router 指南] 中更清楚地说明了它如何融入框架的其余部分。
决策时应考虑哪些因素
服务器操作可减少代码混乱,并默认将敏感逻辑推送到服务器,这同时提高了工作效率和安全状况。这是支持的论点,对于大多数最终是你的正面与你的背面交谈的应用程序来说,它是强有力的。
代价就是纪律。每个操作都是一个公共端口,需要进行如下处理:显式验证、资源级别的授权、外部的域逻辑。那些将其视为细节的人用可见的样板换取无形的风险,而无形的风险是在生产中最糟糕的时刻出现的类型。
如果您正在设计新的 [Next.js11] 应用程序的架构,那么值得从一开始就在信任边界所在的位置进行建模,然后再在整个代码中分配操作。如果您想就这幅画交换想法,请在评论或网络上给我打电话。
另请阅读
- [Next.js 15 和服务器操作:现代突变的权威指南12
- [Next.js 中的缓存和流式传输:性能成为架构决策13
- [Next.js App Router:默认思考服务器指南14
- [2025 年 React 和 Next.js 的国际化良好实践 (i18n)15
- [什么是 React 服务器组件以及为什么逻辑要回归服务器16
- [服务器优先:减轻浏览器负担的架构决策17