2026-11-01·par 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 请求免费。

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

à propos de cette entrée

L'une des entrées de wiki de sijie. L'IA sur ce site est fondée sur le même corpus et répond à la voix de sijie, avec citations revenant à des entrées comme celle-ci — répondre coûte argent à sijie, donc cela attend derrière un code : entrer un code d'accès →