Nextjs和Vercel的几种踩坑知识点

·2238·5 分钟·
AI摘要: 本文深入探讨了Next.js在Vercel平台上的部署与优化,详细解析了SSR、ISR、SSG三种渲染方式及其实现机制,对比分析了cache()与fetch()在不同场景下的应用差异,并针对Serverless环境中的数据库使用挑战提出了解决方案。

背景

在Vercel上部署项目时候,一直以来总会遇到偶尔的报错,但是没有在意。此外,没有深入理解

serverless和普通部署的区别,以及Next.js的一些针对serverless的优化。

Next.js的几种渲染方式

  1. SSR:完全的服务端渲染,来一次请求,启动一个实例,访问一次数据库,拿到一次数据,渲染一次页面,适合实时性非常强的情况。

  2. ISR:这个其实是静态的,放在CDN上,但是会定期重新渲染,然后再投放到CDN上,所以本质是静态的,不涉及服务端的,适合实时性不那么强的情况,速度又要求优先,比如博客。

  3. SSG:这个最好理解,完全的静态,丢到CDN上。

Next.js如何实现这些方式:

  1. SSR: getServerSideProps

  2. ISR: getStaticProps,可以增加了一个revalidate参数,表示重新编译,周期性地投放到CDN

  3. SSG: getStaticProps,不带revalidate参数,完全静态,所以除非重新编译,否则永远不变

关于 cache()fetch() 的理解

在 Next.js 中,应从「实例级别」的运行机制(特别是在 Serverless 场景下)出发去理解。


cache()

  1. 缓存作用域限制在单个 Node.js 实例中

    cache() 是对函数执行结果的缓存,仅在当前的 Next.js 实例中有效。也就是说,如果你在一个实例中多次调用该函数,结果会被缓存,避免重复计算。

    但需要注意的是:

    • 在多实例部署(如 Serverless 或 Vercel)中,每个实例之间的内存不共享,因此缓存是隔离的;

    • 一旦实例销毁(例如 Vercel 的 Serverless 冷启动),缓存也随之丢失。

  2. 与 ISR 配合时的表现

    cache() 可用于 ISR 的构建阶段,用来缓存某些重复执行的函数,提升构建效率。构建完成后,静态页面会被上传到 CDN,后续请求直接命中 CDN,根本不会再执行这些函数或触发 cache()

  3. 与 SSR 配合时的作用

    在 SSR 场景下,cache() 可以减少页面渲染期间的函数重复调用,提高服务端响应效率。但它不能跨请求共享缓存,也不具备增量更新的能力,无法替代 ISR。

    更重要的是,在 Serverless 环境中,由于实例生命周期短且无状态,cache() 缓存无法持久,几乎没有实际意义。


Serverless 环境的 SSR 隐患

在 Serverless 架构下(如 Vercel 的默认部署方式):

  • 每个请求可能对应一个全新实例(cold start);

  • 数据库连接池等长生命周期资源无法复用;

  • 多次快速刷新页面可能引发数据库连接频繁创建、耗尽资源甚至崩溃。

因此,如果要使用 SSR 且依赖数据库,建议:

  • 使用 Prisma Data Proxy 或 PgBouncer 等连接池代理;

  • 避免 SSR 频繁访问数据库,优先使用静态生成或缓存机制。

Serverless 如何使用数据库

在 Serverless 架构中,如果需要持久化云端数据,常见处理方式如下:

  1. 小项目:使用 Upstash Redis(支持 HTTP 请求,天然适配 Serverless)

  2. 大项目:使用 Supabase 或 Prisma + 数据库连接池代理(如 PgBouncer)

传统数据库使用 TCP 长连接并依赖连接池,在 Serverless 中因函数无状态、短生命周期,连接池难以复用,容易导致连接数耗尽。Supabase 通过 PostgREST + PgBouncer 优化了连接复用,但这并不能完全解决问题。

好处是,中间件可以减少每次连接时的鉴权、事务初始化等开销;但本质上连接压力只是从数据库转移到了云函数和连接池代理之间,这个部分仍然是短连接,无法避免。

export const dynamic = "force-static";

值得注意的是,我平时之前不太喜欢用fetch来获取数据,而是采用函数包装prisma,但是这种方式,nextjs是无法识别为ISR的,fetch倒是可以,如果一定要通过prisma也是先ISR,可以手动加上export const dynamic= "force-static";来告诉nextjs,这个是静态页面,然后再加上export const revalidation = 3600实现ISR


才疏学浅,没有深入研究过serverless,根据偶尔白嫖vercel总结的知识点。