2026-11-01·por Sijie Wang

nextjs

Next.js 是一个 React 全栈框架:同一套代码在服务器上渲染页面,在浏览器里让页面可交互,在好几层做缓存,还在页面之前跑请求关卡。

1. 渲染

是什么。 渲染就是把组件变成浏览器能显示的 HTML。Next.js 有几种渲染方式,差别在 HTML 什么时候产生,不在产不产生。

  • SSR(服务器端渲染)。 纯 SSR 没有先存后取这一步:请求来了,服务器当场渲染,浏览器拿到 HTML。接着是水合:浏览器在内存里把组件树再算一遍,对上 DOM,只挂上交互监听。水合不重新取页面,它是让静态页面变可交互。
  • SSG(静态生成)。 HTML 在建站的时候产生。App Router 默认是静态的,除非用了动态函数。generateStaticParams 预建已知的动态地址;dynamicParams 管不在预建集合里的地址怎么办。
  • ISR(增量静态再生)。 带过期时间的静态页:过期时间等于上次生成时间加 revalidate 秒数。请求不延长这个窗口。过了期的请求先给存着的旧页,后台再重新生成(过期先给旧的)。按需再生用 revalidatePath 和 revalidateTag,只能从 Server Action 或 Route Handler 里调。配置在三处:页面级的 export const revalidate、每次取数据的 next: {revalidate}、按需调用。
  • RSC(React 服务器组件)。 服务器组件只在服务器上跑:代码不发给浏览器,可以直接读数据库、文件、密钥。不能用状态、副作用、事件处理。客户端组件标 'use client',发给浏览器、可交互。服务器组件可以把客户端组件当叶子引进来;客户端组件不能引服务器组件,改走 children 或 props 把算好的结果传下去。

流式。 流式的唯一作用是:把一次响应一直开着,算好一段就往下推一段,最后用一个结束信号收尾。经典 SSR 是一次产生一整个 HTML 字符串,按字节顺序来。流式是按顺序先发前面的部分和慢速部分的占位,慢速部分的真内容在流的最后才发,再由一段内嵌脚本在水合之前把它搬进占位里。后面的内容永远不会超过前面的内容。晚补发是个独立于流式的老主意:Ajax(2005 年)就是晚补发,由客户端按写好的声明去拉。真正的区分是谁驱动异步:客户端按写好的声明去拉(Ajax),还是服务端不停地推(流式)。“每段立刻能用”是所有增量下发的通用效果,不是流式独有的点。

2. App Router 与 Pages Router

是什么。 一个框架里的两套路由。Pages Router 把共用导航放在 _app 里;App Router 把共用导航放在 layout 里。layout 一层一层嵌套。

导航。 导航是靠地址换:地址变了,App Router 找到页面和它的一串 layout,没变的 layout 层不重新跑。

复用。 这里的复用是浏览器渲染出来的结果被复用,不是代码复用。App Router 的“不做”(没变的层的导航代码不跑)是复用的推论。Pages Router 没有渲染结果复用:每次导航都重新算导航,只是页面上看不出变化。

现状。 App Router 没有取代 Pages Router,两套都活着;App Router 更新,是主推的那套。

3. 缓存

三层加一个非层。 每一层只在自己的内容变了的时候才动。

  • 数据层(Data Cache)。 取来的数据,存在服务器磁盘上,跨请求共用。它存的是共用的原材料,不是页面。
  • 整页层(Full Route Cache)。 整个渲染好的页面,也在服务器磁盘上。重启还在,重新部署就没了。
  • 浏览器层(Router Cache)。 访问过的页面,存在浏览器内存里。标签页一关就没了。
  • 同一次算(Request Memoization)。 不是存的一层:一次渲染里同一份数据取两次,只取一次。layout 的复用是跨页面的,同一次算是同一次渲染里的。

三层之外还有前层(CDN:离访问者近的一份拷贝,访问者先问它,问不到再问服务器),以及浏览器自己的 HTTP 缓存,它不是浏览器层。

为什么是磁盘不是内存。 重新算(取数据加渲染 CPU)比读一次磁盘贵得多。操作系统反正会把常读的文件留在内存里(页缓存)。内存小、贵、重启就没(冷启动时全得重算),在 serverless 里还按每次调用算;磁盘大、便宜、重启还在,是最合算的点。

磁盘怎么回收。 没有按大小自动淘汰。过期(下次访问重新取了盖掉)、手动 revalidatePath 或 revalidateTag、重新部署清掉缓存目录,就这三条路。

个性化。 框架不需要“用户”这个概念,它只看这次渲染用没用请求带来的东西。调 cookies()、headers()、searchParams(请求时才有的接口)就是给渲染打了个标记:打了标记的地址不能存着共用,每次访问都重新渲染;没打标记的能存。登录状态是你自己代码的事,框架只把浏览器送来的凭证往下传。Cookie 影响的是整页层(地址变动态),不直接动数据层的秒数;动态渲染时共用的数据还是从数据层来。

写错会怎样。 个人内容要是随手写进了共用层,存量会跟着用户数炸,更先出问题的是串用户:共用层的键默认不带“这是谁的”,个人数据存进去就会发给别人。正确的写法:共用的部分存一次,个人的部分永远不存,每次访问现取,或者在浏览器里算。

浏览器自己的 HTTP 缓存不是浏览器层。 浏览器层是 Next.js 自己的代码在浏览器内存里管路由器缓存:留什么、多旧算旧,都按 Next.js 的配置来,要新数据就是向服务器新发一次请求,没有 HTTP 头协商。浏览器自己的缓存是协议协商:服务器在响应头里说存多久或不存,浏览器照办;过期后浏览器拿着内容指纹问“变了没”,服务器回 304(没变,继续用)或 200(变了,给你新的)。服务器是靠响应头管浏览器自己的缓存,不是管浏览器层。

部分预渲染。 同一个页面,数据变了,静态不变的部分不变:静态部分预渲染好存着,动态部分留占位(Suspense),每次访问现算再填进去。是比较新的机制,不同版本的有无和配置不一样。现在的文档分新的(Cache Components,v16)和旧的(Previous Model)两套;取数据的默认也不一样:现在的文档默认不缓存,v14 及之前默认一直缓存(revalidate=false 就是无限期)。

缓存也是安全面。 框架会自动做安全相关的决定:不带用户身份的缓存键、中间件跑没跑的判断。自动决定错了就是漏洞,不是小毛病。两个例子:CVE-2025-29927(一个请求头绕过中间件的登录检查),CVE-2024-46982(一个请求头把不该存的地址拉进共用缓存,给下一个访问者)。Next.js 老出 CVE 也是这个原因:面太大(路由、渲染、缓存、中间件全在一个包里,全对着不可信的请求),自动做安全相关的决定,用的人最多所以查得最严、披露最快,App Router、RSC、server actions 这些新协议本身毛病密度就高。

4. 自带优化

next/image。 很大的原图只显示很小,等于白下载:这个组件给一份尺寸合适的。 高密度屏幕在同样显示尺寸下要两倍的物理像素,所以它是按屏幕给,不是永远按显示尺寸给。

next/font。 字体存在自己的服务器上,不用向外请求。只留用得着的字形(子集),文件更小。占位字体按真字体的尺寸调过,真字体到了换上去文字不动。老办法是外链样式表,先是空白或后备字,然后全都跳一下。字体文件本身存在服务器磁盘上,是静态文件。占位用的尺寸数是建站的时候从真字体文件的 metadata 里读出来、写进页面样式里的;占位本身是设备自己的系统字体,不用下载。

next/script。 第三方脚本(统计、广告、聊天框)的加载策略:页面可交互之前、页面可交互之后(默认)、空闲时。这跟水合不是同一个机制,但有关联:默认特意排在水合之后,免得外来脚本抢资源、拖慢水合。水合是让页面自己变可交互,脚本策略是管外来的脚本什么时候插进来。

5. 中间件与 Edge Runtime

中间件。 请求进页面之前先过的一道关:查登录、没登录就拦回去、按地区分流。

Edge Runtime。 轻量运行环境,只有浏览器那套标准接口,没有 Node 才有的东西(比如读磁盘),跑在离用户近的边缘节点上,启动快,只适合小的、快的活。存在的原因是中间件每个请求都要跑,跑得越近越快。

前端框架为什么揽这活。 中间件必须跟路由、渲染用同一套规则,分开两处写,两边一不一致就出漏洞。框架揽的是“怎么写、什么时候跑”这个模型,全球节点还是平台(Vercel、Cloudflare)在运维。这是个有争议的设计。反方:耦合(代码被部署的地方绑住)、面越铺越大(CVE 越来越多)、跟平台绑紧。 正方:一致,小团队不用自己搭基建就能用上全球边缘。到了企业级这个 tension 更尖:真的企业级项目前后端分开,后端也得要边缘,除非全家桶(Vercel 加 Next.js),否则框架的边缘和后端的边缘之间的耦合面非常大。大公司往往反过来:边缘层归网关、平台统一管,前端框架只管页面。

6. 部署

真正要了解的不是云本身,是框架功能跟部署地的匹配程度。 同一个功能,换个部署地,能不能用、好不好使,是不一样的。缓存在哪、谁管,人多了怎么办,花多少钱,数据放哪,这些是通用的云问题;Next.js 独有的只有功能跟部署地的匹配。

  • 放 Vercel。 我们讲过的功能全能用,缓存、中间件、边缘、图片优化,开箱即用。
  • 自己部署。 页面渲染、缓存层都能用,都在自己服务器磁盘上;边缘没了,没有全球节点,中间件在自己服务器上跑,远的用户还是慢;人多了自己加机器;重新部署缓存就没了。
  • 其他云(Cloudflare、Netlify、AWS)。 用转接器去对接,能用大部分,但有限制、有差别,不是原生的。Cloudflare 是反过来的形状:平台先行,框架随便选。Workers 加 Pages 加 Vite 插件让 React、Vue、Svelte 这些都能在 Workers 上跑全栈,边缘归平台管、框架去适应。免费层每天 10 万次 Workers 请求免费。

选部署地就是选这张对照里你能接受的那一行。

sobre esta entrada

Una de las entradas de wiki de sijie. La IA en este sitio está anclada en el mismo corpus y responde en la voz de sijie, con citas que vuelven a entradas como esta — responder le cuesta dinero a sijie, así que espera detrás de un código: ingrese código de acceso →

nextjs — Sijie Wang