Vercel Edge Functions 用在内容站:什么时候值得

Edge Functions PPT 上很漂亮,但大多数内容站根本不需要。本文讲清 Edge 真正能赢的场景、Node serverless 更合适的情况、以及静态才是答案的时候。

Vercel Edge Functions 跑在 V8 isolate 上、离用户最近、冷启动几十毫秒——听起来稳赚。但别忘了预生成的静态页比这还快,而 Node serverless 能用全套 npm。本文讲清 Edge 在内容站上什么时候是对的工具,什么时候反而吃亏。

问题背景

Vercel 有三种计算目标:静态(build 时预生成)、Node serverless(完整 Node 运行时,冷启动约 300ms)、Edge Functions(V8 isolate,冷启动约 50ms,跑在 18+ 区域)。Edge 有硬限制:不能用原生 Node 模块、代码 4 MB 上限、请求体 1.5 MB、API 受限。内容站绝大部分应该走静态,其余情况本文讨论。

判断标准

  • 每次页面加载都打函数,真实用户指标里看得到冷启动尖刺。
  • 在服务页面之前就要做地理路由、A/B 测试或鉴权——不是之后。
  • 函数体积小(1 MB 以内)、纯 JS、不需要文件系统或原生模块。
  • 离函数区域远的用户 TTFB 明显高。

快速结论

如果干的活是”重写、跳转、按地区分流、设 cookie、读 header”——Edge 赢。如果是”渲染页面、生成 OG 图、用胖 ORM 查数据库”——选 Node serverless,或者直接预生成。纯内容站静态胜过两者。

Edge Functions 真正有优势的场景

三个 Edge 在内容站上明显比 Node serverless 强的模式:

  1. 中间件里的按地区跳转。 根据 Accept-Language 或国家码把 / 跳到 /en//zh/——Edge 跑在缓存前,开销大概 20ms:
// middleware.ts
import { NextResponse, NextRequest } from 'next/server';

export const config = { matcher: ['/'] };

export function middleware(req: NextRequest) {
  const country = req.geo?.country ?? 'US';
  const lang = country === 'CN' || country === 'TW' ? 'zh' : 'en';
  return NextResponse.redirect(new URL(`/${lang}/`, req.url));
}
  1. 带 cookie 持久化的 A/B 测试。 首次访问分桶、写 cookie、之后保持稳定。分桶决策必须在缓存之前,中间件正合适:
// middleware.ts —— 分桶并重写到变体
import { NextResponse, NextRequest } from 'next/server';

export const config = { matcher: ['/pricing'] };

export function middleware(req: NextRequest) {
  const existing = req.cookies.get('ab-pricing')?.value;
  const bucket = existing ?? (Math.random() < 0.5 ? 'a' : 'b');
  const url = req.nextUrl.clone();
  url.pathname = `/pricing-${bucket}`;
  const res = NextResponse.rewrite(url);
  if (!existing) {
    res.cookies.set('ab-pricing', bucket, { maxAge: 60 * 60 * 24 * 30 });
  }
  return res;
}
  1. 鉴权预览。 在边缘读 session cookie,把草稿重写到 preview 分支,没权限的直接拦下,不用回 Node origin。

值得记一下的真实延迟数字

2026 年 Vercel 的粗略预算,us-east-1、热缓存:

  • CDN 上的静态页:TTFB 20-40ms。
  • Edge Function(热):在 CDN 之上再加 30-60ms TTFB——匹配到的路由上,函数仍在缓存之前跑。
  • Edge Function(冷):某区域首次请求 80-150ms。
  • Node serverless(热):100-200ms。
  • Node serverless(冷):300-1500ms,看 bundle 大小。

如果用户全球、函数干的活又轻,Edge 冷启动可能比 Node 热还低。如果函数被命中得少,Node 冷启动就是最坏情况。

该用 Node serverless 的场景

  • @vercel/og 生成 OG 图、字体从 CDN 加载——Edge 能跑,但需要从文件系统加载资源时 Node 更舒服。
  • API 路由要打 Prisma、Drizzle 或任何官方还没正式支持 Edge 的 ORM——大部分仍然要 Node。
  • 任何用原生依赖的:sharppuppeteernode-canvas——这些在 Edge 上根本跑不起来。

两者都不对、静态才赢的场景

  • 内容按已知节奏更新的文章页。build 时预生成,更新走 ISR 或 on-demand revalidation,函数完全省掉。
  • sitemap 和 robots——build 时生成,CDN 直出,零函数调用。
  • 数据量在 200 KB 以内的搜索 / 过滤 UI——跟着页面发出去,前端直接过滤。

容易踩的坑

  • “为了个性化”把文章页放到 Edge Function 后面——CDN 缓存全废,每次请求都多一份延迟。
  • 在 Edge route 里 import 了 Node-only 模块,部署时才发现——本地 dev 也要设 runtime = 'edge'
  • 忘了 Edge Function 即便命中 304 也计用量——中间件跑在缓存之前。
  • 在 Edge 里读集中式数据库——函数快,但从各地区回数据库的 round trip 一点不快。要么用全球复制存储(Upstash、PlanetScale edge driver),要么预生成。
  • 用 Edge 做 OG 图,bundle 字体后撞 4 MB 上限——换 Node。

FAQ

  • Edge Functions 比 Node serverless 便宜吗?: 单次调用通常便宜。但中间件每次请求都跑,逻辑放错位置反而总成本更高。
  • Pages Router 能用 Edge Functions 吗?: 能,API 路由里 export const config = { runtime: 'edge' },或者写 middleware.ts
  • Edge 上能用哪些 API?: Web 标准 API(fetch、Request、Response、crypto.subtle、streams)。没有 fs、没有原生模块、Buffer 也受限。
  • Astro 支持 Edge 吗?: @astrojs/vercel adapter 有 edge 模式,但大多数 Astro 站是静态的,根本不需要。
  • Edge 会让我 Lighthouse 分数变高吗?: 仅当你的 TTFB 卡在 Node 冷启动上才有用。配好缓存头的静态页 Lighthouse 上已经赢了。

相关阅读

标签: #独立开发 #Vercel #部署 / 托管 #edge #性能