思考啊SIKAOA
4 分钟阅读幻灯片

当 26MB 的 RSC Payload 压垮博客:一次 502 错误的排查

今天下午,博客突然打不开了。
打开 sikaoa.com,看到的是 Vercel 的 502 错误页面,代码是 FALLBACK_BODY_TOO_LARGE。

说到这个,我第一反应是文章太多了,但转念一想——博客是静态生成的,不应该出现这种问题。

排查过程

我进到本地构建输出目录,用 ls -la 看了一眼文件大小,结果吓了一跳:

  • index.html — 26.3 MB
  • index.rsc — 22.2 MB

一个博客首页,怎么会生成 26MB 的 HTML?这根本没法加载。

找到根因

打开 index.rsc 检查,发现里面有 3600 多个 excerpt 字段
说明整个文章库(3583 篇)被序列化到了 React Server Components 的 payload 中。

再翻代码,问题出在 getPostsByCategory() 这个函数上:
它返回的每个 Category 对象都包含一个 posts: Post[] 数组——也就是说,每个分类下有多少文章,就把多少文章完整塞进去。

而首页的 CategoryNavSidebar 都是客户端组件(加了 "use client"),Next.js 在序列化 RSC payload 时,会把传给客户端组件的 props 全部内联到 HTML 里。
于是,3583 篇文章的数据直接塞进了首页 HTML

修复方案

修复其实很简单:

  1. app/page.tsx 中,把 categories 映射为只包含 namecount 的轻量对象
  2. 修改 CategoryNavSidebar 的 props 类型,不再接收完整的 posts 数组

改完重新构建,效果立竿见影:

  • index.html — 101 KB(从 26.3 MB 降了 260 倍)
  • index.rsc — 33 KB(从 22.2 MB 降了 670 倍)

经验总结

这次问题的本质是:服务端的数据不小心泄露到了客户端的序列化流程中。
在 Next.js App Router 中,任何传给客户端组件的 props 都会被序列化到 RSC payload 中。
如果这些数据包含大数组,就会直接导致 HTML 体积爆炸。

以后设计组件接口时,一定要分清楚哪些数据是真正需要在客户端用的,别一股脑全传过去。