把一个纯客户端渲染的React应用改造成服务端渲染,最直接的收益就是首屏速度和SEO效果。而在Node.js生态里做SSR,Next.js几乎是不二之选,配合Vercel的Serverless平台,可以做到不买一台服务器就上线完整的SSR应用。这篇文章会从SSR的运行原理讲起,逐步展开Next.js的渲染模式、Vercel的Serverless机制,以及部署时的实战细节。

一、Next.js的服务端渲染是怎么工作的
传统的客户端渲染流程是:浏览器先下载一个几乎空白的HTML壳子,再拉取打包后的JS文件,React执行之后才把页面内容挂载到DOM上。用户看到内容的时间被推迟到了JS下载和执行之后。SSR则把这一步搬到了服务端,Node.js进程在收到请求后,直接执行React组件的渲染逻辑,把完整的HTML字符串返回给浏览器,浏览器拿到手就能立即呈现内容。
Next.js在这个基础上做了进一步的拆分。静态生成(SSG)在构建阶段就生成好HTML,适合内容不常变化的页面;而真正的动态SSR则通过getServerSideProps或App Router中的服务端组件实现,每个请求都会重新执行数据获取和渲染。下面是一个经典的Pages Router写法:
export default function Page({ data }) {
return <div><h1>{data.title}</h1><p>{data.content}</p></div>;
}
export async function getServerSideProps(context) {
// 每次请求都会执行,可以从context中拿到query、headers等
const res = await fetch(`https://api.ipipp.com/articles/${context.params.id}`);
const data = await res.json();
return { props: { data } };
}到了App Router时代,写法变得更简洁:服务端组件默认就在服务端执行,async组件内部可以直接await数据,配合loading.tsx还能实现流式SSR,把页面拆成多个chunk逐步推送给浏览器。这种方式对慢接口特别友好——页面框架先渲染出来,数据块到了再补上,用户感知到的白屏时间进一步缩短。
需要注意的一点是,SSR代码运行在服务端,凡是依赖浏览器API的代码(比如window、document)都必须放到useEffect里或者用动态导入加上ssr: false选项,否则构建或运行阶段会直接报错。这是从CRA迁移过来的开发者最容易踩的坑。
二、Vercel的Serverless运行机制
Vercel部署Next.js应用时,会把每个SSR页面编译成一个独立的Serverless函数(在新的架构下是基于Edge或Node.js runtime的Lambda函数)。也就是说,你的应用不是跑在一个常驻的Node进程里,而是被拆散成一堆按需执行的函数。请求到达时函数被拉起,执行完渲染就返回结果,空闲时平台自动释放资源。
这种机制带来的最大好处是弹性伸缩。流量高峰时平台自动扩容,不需要你预估峰值、配置机器;流量低谷时又几乎零成本。对于访问量波动大的内容型站点,比如活动页、资讯站,这个优势非常明显。代价则是冷启动:函数长时间未被调用后会被回收,下次请求需要重新初始化运行时,加载依赖包,这个时间可能从几十毫秒到一秒不等。
缓解冷启动有几个实用手段。第一是精简依赖,Next.js对每个函数会做Tree Shaking,只打包页面实际引用的模块,所以尽量不要在页面文件里引入整个大型库。第二是合理利用Vercel的Edge Runtime,它基于轻量级Web标准API,冷启动比Node.js runtime快一个量级,适合做轻量的动态渲染、鉴权、重写等逻辑。第三是让数据库与函数同区域部署,减少数据获取的往返延迟。
本地调试Serverless行为可以在项目里安装vercel CLI,用vercel dev在本地模拟函数环境,它比单纯的next dev更接近线上真实表现,比如环境变量注入方式和函数执行边界都和线上一致。
三、部署实战与缓存策略
部署流程本身极其简单:把代码推到Git仓库,在Vercel控制台导入项目,平台会自动识别Next.js并执行构建。构建命令和输出目录默认配置即可,无需手写Dockerfile或者Nginx配置。之后每次push代码,Vercel自动构建并生成预览部署,合并到主分支则触发生产部署,全程不需要碰服务器。
生产环境下,缓存是决定SSR性能的关键。Vercel会在函数返回的响应上处理CDN缓存,你可以在getServerSideProps里通过res.setHeader设置Cache-Control头,让同一URL的渲染结果在边缘节点缓存一段时间,比如:
export async function getServerSideProps({ params, res }) {
const data = await getProduct(params.id);
// 边缘缓存60秒,浏览器侧不再重复缓存
res.setHeader('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300');
return { props: { data } };
}这段配置的含义是:CDN缓存60秒内的渲染结果直接命中边缘节点,不再触发函数执行;60秒到360秒之间命中旧缓存的同时后台刷新,用户始终拿到秒级新鲜的数据。对于内容有一定时效性但允许短暂延迟的页面,这种策略能省下大部分函数调用开销,费用和延迟双双下降。App Router中则更推荐用fetch的缓存配置或revalidate选项来做数据层的缓存控制,粒度更细。
四、与传统Node服务器部署的对比与选型
如果自己用Node服务器跑SSR,通常是next build之后next start,前面挂一层Nginx做反代和缓存。这套方案的优点是进程常驻、没有冷启动,长连接和WebSocket支持也更自然。缺点是你得自己管机器、证书、日志、监控、灰度发布,流量突增时还得手动扩容,对小团队来说运维负担不小。
Vercel这类Serverless方案则把上面的运维项全部托管了,附带自动HTTPS、全球CDN、预览部署、回滚等能力。费用按用量计算, Hobby额度对小站点基本够用。但也有边界要清楚:函数执行时长有上限,不适合长时间计算;依赖文件系统和长连接的场景会受限;如果数据库在国内而函数部署在海外节点,跨区域延迟会拖慢整体响应,这时要么把数据源也搬到靠近函数的区域,要么考虑自建方案。
总体选型建议是:内容型、营销型、流量波动大的站点优先Next.js加Vercel的组合,开发效率和运行成本都占优;有大量长连接、本地文件操作或合规要求的业务,则自建Node集群更稳妥。无论哪种路线,先把渲染逻辑与浏览器环境解耦、控制好缓存策略,都是做好SSR绕不开的基本功。
Serverless SSRNext.jsVercel部署修改时间:2026-09-05 09:40:45