惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

Grtsinry43 的前端札记

一些忙碌之外的余温 我是怎样使用 AI Agent 写代码的 从头开始的勇气 列车上的生活 分享一点体测的小事 「手搓系列 02」深入浅出 Agent Skills:架构、实现与思考 路的尽头还是路 二十一岁,然后...... 我患上了 token 的瘾 Xiaomi 17 标准版刷机折腾记:解锁、官改ROM与必备模块 思考 在焦虑与代码中缓慢前行 从 v1 到 v2,谈谈这个简单博客背后的架构演进与实现 Go 语言初体验:Less is more,一种丑但可靠的工程美学 职规赛,一次特别的体验 2025 年终总结——从晨光到雾散,化经历为成长 2025 实习札记:关于一场未完成的迁徙与落地 从想法到实践:在无序的生活里,试图用代码敲出一点秩序 PureFlow 简析:用 Kotlin 跨平台构建 RSS 阅读器 命运开了个无情的玩笑 「手搓系列 01」 从零搭建 Vue 文档站,学习从静态生成到语法解析 手把手带你玩转 Monorepo,拥抱现代前端开发新范式 好久不见,这是一份来自作者的独白
新时代的 PHP:RSC 的边界错位与工程代价
grtinry43 · 2025-12-14 · via Grtsinry43 的前端札记

讽刺的是,这篇文章,也就是你看到这个网站,正在运行在 Next.js 上,但由于无法承受的问题和维护压力,我已经很认真地把“放弃 Next.js”提上日程了。

Next.js 本身我正在用、也在骂。原因不复杂:这两年最“新时代 PHP”的东西,不是某个新框架,而是 前端在不自知的情况下,被推去承接后端该承担的安全边界与运行时复杂度——而 React Server Components(RSC)正是这件事的放大器。

我会用一种比较“理性地骂”的方式,把事情讲清楚:

RSC 到底是什么;它为什么天然把边界搞得很危险;最近这次 RSC 相关的严重漏洞到底发生在什么位置;Next.js 与 Vercel 又是怎样把这些能力包装成“工程默认选项”;以及这些选择的工程代价最终转为了什么。


零、先叠甲:“新时代 PHP”到底在说什么

在正文开始前,我想先给这篇文章定个调,以免误伤友军:

  1. 我并不否定 Next.js 在效率上的统治力:对于独立开发者、验证型 MVP(最小可行性产品)、或者内容型网站(博客、文档),Next.js + Vercel 依然是目前地球上最快的上线组合。这种“一把梭”的爽感,我是认可的。
  2. “新时代 PHP”不是贬义词,而是架构描述:正如 PHP 曾凭借“请求即脚本”的低门槛撑起了半个互联网,RSC 也在试图降低全栈门槛。但我所担忧的,是它在 不经意间 复刻了当年 PHP 混合开发时期的“安全黑洞”与“耦合泥潭”。
  3. 我的视角偏向“严谨工程”:作为一名习惯了 Spring Boot/Java 后端架构,或者是 ktor fiber fastify,同时主要学习前端领域的开发者,我对 “边界(Boundary)” 极为敏感。这篇文章的核心冲突,在于 “前端追求极致 DX(开发体验)”“后端追求极致安全与稳定” 之间的天然矛盾。
  • 以前:前端是前端,后端是后端。接口契约、鉴权、审计、限流、WAF、灰度,都在后端层解决。

  • 现在(RSC/Server Actions 的兴起):把“后端能力”塞进 React/Next 的文件与组件里,用 use server 把函数变成“远程可调用逻辑”。官方甚至明确表达过“你可以不需要手写 API Route”。 Next.js13 的叙述

这不是“全栈”那么简单,这是 把接口面向公网的语义,无感的形式伪装成了组件内部的语义。语义伪装的后果通常只有两种:安全事故,或者工程事故——最好两者别一起来。

一、RSC 到底是什么:它不是 SSR 的升级,而是“协议 + 运行时分裂”,也就是,边界错位从协议层就开始了

如果只看铺天盖地的宣传,RSC 很容易被误解成“更快的 SSR”或“把组件放到服务器渲染”。但 React 官方对 Server Components 的定义里有个关键点:它运行在一个“与客户端应用或 SSR 服务器分离的环境”,并且输出的不只是 HTML。Server Components

更准确地说,RSC 带来三件事:

  1. 组件分层变成运行时分层

    • Client Components:在浏览器跑,拿到 JS bundle。

    • Server Components:在服务器跑(可能是构建时,也可能是请求时),可以直接访问数据库/文件系统等服务器资源。所以你可以看到,官方甚至搞了一个教程建议你在 RSC 写 sql,然后使用 Suspense 做流式传输。App Router: Getting Started | Next.js

  2. 传输的不是页面,而是“可恢复的组件树数据”(Flight payload) 你可以把它理解为:服务端把一棵 React 树编码为一种可流式传输的数据结构,客户端再把它解码/拼装回 React 状态,也就是本身他就和 SSR 是完全不同的。

  3. 组件开始携带“能力”
    一旦你允许“Server 侧函数可被触发”(例如 Server Actions/Server Functions),你就不再只是渲染 UI:你是在暴露一套“从浏览器直达服务器逻辑”的通道,那这里就很危险了,因为这就从获取运行结果,变成了一种类似 RPC(远程过程调用)。Next.js

这第三点,就是边界错位的根源。


二、Flight 协议的现实:它必然涉及“反序列化”,而反序列化就必然是风险点,配合 JS 本身的设计那就无所不能了


很多人听到“反序列化漏洞”就条件反射:又是 Java 那套? 但这里不是对象流,而是 协议层为了让 React 树可恢复,必须做的解码过程

React 的实现里,你能看到它对 payload 的处理方式:JSON.parse 并不是直接 parse 成普通 JSON,而是带了一个自定义 reviver(_fromJSON),用来把特殊标记字符串(例如 $ 开头)解释成 Promise、Server Reference、Map、Set、FormData、Date、BigInt 等结构。

https://github.com/facebook/react/blob/323b6e98a76fe6ee721f10d327a9a682334d1a97/packages/react-server/src/ReactFlightReplyServer.js https://github.com/facebook/react/blob/323b6e98a76fe6ee721f10d327a9a682334d1a97/packages/react-server/src/ReactFlightReplyServer.js

例如:

以及 reviver 里对 $ 前缀的分派:

这些代码只是说明一个事实:

RSC 的正常工作方式,就是在服务器端“解码外部输入”并恢复出可执行/可解析的结构。 你一旦把“可触发的服务器函数”也绑在同一套通道上,安全边界就从“HTTP API”滑向“协议解码器”。

这就是架构选择的必然后果,毕竟安全总要有模块负责。

Java 的 ObjectInputStream 踩过,Python 的 Pickle 踩过,现在轮到 JS 的 Flight 了。


三、这次离谱事件的原因:不是业务逻辑,而是解码器被当成了能力网关,责任边界到了前端


不久之前,React 官方发布公告:RSC 存在一个“未认证的远程代码执行(RCE)漏洞”,可通过利用 React 解码发送到 React Server Function 端点的 payload 触发。

React https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components

第三方安全团队的分析进一步强调了它的性质:这不是某个业务接口没鉴权,而是 Flight/RSC 相关的“处理链路”出现了可被利用的点,导致在默认配置下就可能被打穿。wiz.io

并且,这类问题会天然产生“生态级连坐”:

  • React 层:CVE-2025-55182(React/Flight/RSC 相关)

  • 框架层:Next.js 等实现 RSC/Server Actions 的框架会一起进入受影响范围

在这个事故发生的时候我还刚好甲流,发烧很难受,但是还不得不强撑着起来更新依赖

在这次事件中,责任边界发生了变化

以前你写后端 API,你会默认:

  • 输入校验是业务层的事

  • 鉴权/鉴别来源是网关/中间件/后端统一层处理的

  • 序列化/反序列化是你可控的

而在 RSC/Server Actions 的组合里,很多工程的默认形态是:

  • 浏览器发一个“协议包”

  • 框架解码恢复结构

  • 框架再把它路由到某个服务器函数

解码器变成网关,这就会让“协议实现细节”直接进入你的威胁模型。React


四、继续复盘,事情的严重:Next.js 把能力包装成默认姿势,甚至开箱即用:于是前端开始背后端的锅


于是这个时候主推 App Router 的 Next.js 出场了。

如果 Next.js 只做“传统前端 + SSR”,其实还没那么灾难。真正的拐点在于:Next.js 把 RSC/Server Actions 作为 App Router 时代的主叙事之一,并明确描述 Server Actions 是 在服务器执行的异步函数,并且可在 Server/Client Components 中使用Next.js

那事情就变得微妙了:

你把函数写在前端项目里,但它会在服务器跑;你在组件里调用它,但它是“后端入口”。

到这里,“前端插手后端开发”的现实就出现了:

  • 这条链路一旦出安全问题,你不能再说“后端会兜底”,因为后端入口就在 Next 项目里。

  • 作为前端开发,你不能再说“我们只写页面”,因为你实际部署的是一段“可被触发的服务器逻辑”。

  • 你甚至很难用传统后端的方式给它加网关、加 WAF、加统一鉴权层,因为框架已经替你决定了请求应该如何被解释。

Next.js 当然意识到了风险,于是也着重添加了安全相关的配置和能力。Next.js 但这件事本身看起来啊就很荒谬:你看起来在写“组件”,实际上你在配置后端的安全策略。

而现实里,因为 Nextjs 将开发后端的门槛降得太低了,很多“纯前端开发者”并不具备这套安全心智模型:他们会把它当成“更舒服的表单提交方式”,直到某天看到公告写着“Unauthenticated RCE”。React

这就是强制前端插手后端的后果,前端想把后端写成语法糖。

然后再把后端能力塞进前端默认工程,假装这只是 DX(开发体验)。


五、再说 Vercel:用 Next.js 做壳,引流平台能力,然后把复杂度外包给用户


这里我不否认 Vercel 的产品力,它确实把部署体验做得极致,并且它也提供防护体系(包括平台级防护、以及可配置 WAF/Firewall)。Vercel

但问题在于:Next.js 的很多“卖点”,在工程上并不是“框架能力”,而是“平台叠加能力”。

举两个典型例子:

1)ISR:听起来是框架特性,实际是缓存/失效/函数编排的一整套系统

Next.js 文档会告诉你如何做 ISR、如何触发再生成、如何 revalidate。Next.js Vercel 的文档则会进一步解释 ISR 在其平台上会如何落到具体的 Function/缓存与配置上。Vercel

工程现实是:

  • 你以为你在用“Next.js 特性”;

  • 你实际在绑定“某个平台对缓存失效与边缘分发的具体实现”。

这不是不能用,而是你应该清楚:这类特性会把你从“框架迁移”推到“平台迁移”。

2)“中间件”这个词本身就带歧义:它并不在你的服务中间,而是在 Edge Runtime

Next.js 早期版本 Middleware 只支持 Edge runtime,不能用 Node.js runtime。Next.js 而 Edge Runtime 又意味着:你拿到的是 Web API 语义、受限的运行环境,与 Node.js 的能力集不同。Next.js

所以很多时候你写 Middleware 的体验是:

  • 名字叫“中间件”,你以为它像后端的 middleware/filter;

  • 实际它更像“边缘网关脚本”,能力受限、调试困难、行为受运行位置影响。

把它叫 middleware,不是错,但它会天然误导大量开发者建立错误心智模型:以为自己在写“后端中间件”,其实是在写“边缘逻辑”。

这样,你以为它值得信赖,然而实际上只是展示他们平台能力的一个手段。

说的更直白些,你以为你写的是标准 Web 代码,实际上你写的是 Vercel 专用的 DSL


六、工程代价清单:不是学一下就会,而是你要多维护一个世界观


到这里,骂点就不应该停留在“Vercel 坏”“Next 坏”“RSC 坏”,而是要落到工程代价——因为这才是你会长期为之付费的部分。

1)运行时分裂:Node、Edge、Client、Server Component 环境并存

Next.js 自己就把 runtime 拆成 Node 与 Edge 两套,并说明能力差异。Next.js 而 RSC 又把组件分成 Server/Client 两类。React

你最终维护的是一个矩阵:

写法运行位置API 能力风险点
Client Component浏览器浏览器 APIXSS/依赖链
Server Component服务器/构建服务器资源数据泄露/边界混乱
MiddlewareEdgeWeb API 子集行为不一致/调试困难
Server Action服务器后端入口鉴权/来源/反序列化

作为全栈框架的使用者,它只是事实:你需要为每个格子建立正确预期,否则问题会以“看起来像 bug”的方式出现。

2)安全边界内陷:从“API 网关/后端鉴权”变成“框架配置 + 协议解码链路”

这次事件已经告诉我们:攻击面不止是业务 API,而是 RSC/Flight/Server Functions 的解码链路。React

Nextjs 成功证明了 全栈不难,难的是把责任边界划清楚。

3)平台耦合:迁移成本从“换框架”上升到“换平台能力组合”

ISR、Edge、WAF、以及各种“默认最佳实践”,在 Vercel 上确实丝滑。Vercel 但当你想把它搬走(自建、换云、甚至只是加一层代理),你就会发现:你迁移的不只是代码,还有一堆隐含假设。


七、最后补一刀:AI 生成代码默认 Next.js 起手,是在扩大这种错位


现在很多 AI 生成前端项目的默认姿势,基本都是:Next.js + App Router + Server Actions + Shadcn/ui + 一堆平台最佳实践模板,拿过来一把梭哈。Vercel 自己也在把生成 UI/生成代码与 Next.js 工作流绑定( v0 就是他们家的代表,额不是 VoidZero 那个 v0,是 v0.dev)。

问题不是 AI 生成了 Next.js,而是:

  • AI 会把“默认最流行模板”当成“默认最正确架构”

  • 它很少提醒你:我创建的是全栈项目,这里的 Server Actions 是后端入口、这里的 Middleware 跑在 Edge、这里的 ISR 会平台耦合、这里的安全边界需要你自己负责

  • 于是新手更容易在不理解 RSC 的情况下,把项目推到全栈默认形态

当理解成本被隐藏,风险成本就会延后爆炸。然后大家再回来补课:什么是 Flight、什么是 reviver、什么是来源校验、什么是边缘运行时差异——这就是工程代价,一个激进框架背后的,一个把后端当前端语法糖来写的工程代价。


总结:我为什么说这是“新时代 PHP”


我不反对 RSC,也不否认它在某些场景能带来性能与工程收益。我反对的是:

  1. 把后端能力伪装成组件语法糖,让不具备后端工程化能力的人去写后端入口。

  2. 把协议解码链路推成事实网关,让安全问题从业务层上移到框架实现细节。

  3. 用平台体验裹挟框架路线,让特性越来越像为平台服务,迁移越来越像掏空重来。

之所以人们在放弃 Next.js,不是因为它写不了什么,恰恰相反他有面面俱到的能力;而是因为我不想再把一个前端工程,硬凑成一个后端工程,然后在漏洞公告出现时才意识到:原来我部署的不是页面,是一段可被触发的服务器逻辑。

写这篇文章,并非要号召大家明天就卸载 Next.js 回去写 JSP。 技术的螺旋上升总伴随着代价。React 团队探索 RSC 的勇气值得敬佩,Vercel 想要统一 Web 开发流的野心也令人惊叹。但在铺天盖地的营销叙事中,我们作为一线工程师,必须保持 冷眼旁观 的能力。

我们不能因为 Vercel 演示里的 Demo 很炫酷,就忽略了背后那个正在泄漏数据库连接的 Lambda;也不能因为 use server 写起来很爽,就忘记了此时此刻你正在裸奔。 理性地评判,是为了在它把我们的工程搞崩之前,先搞清楚底线在哪里。