Vercel Edge Functions 是平台近年来最核心的差异化能力之一:基于 V8 Isolate 技术的 Edge Runtime 让代码在全球 100+ 边缘节点就近执行,延迟降到 50ms 以内,冷启动接近零。对于 AI 流式响应、全球化路由、A/B 测试、访问控制等场景,Edge Functions 几乎是无可替代的选择。本文从底层架构到生产代码,全面拆解 Edge Functions 的能力边界。
一、Edge Runtime 与 Node.js Runtime:核心区别
1.1 架构差异
Node.js Runtime(Serverless Functions)
└── 完整 Node.js 容器
├── 完整 fs / net / crypto / buffer API
├── npm 生态(Prisma、sharp、bcrypt 等)
├── 冷启动:50-500ms
└── 执行限制:10s(Hobby)/ 60s(Pro)
Edge Runtime(Edge Functions)
└── V8 Isolate(轻量沙盒)
├── 类浏览器的 Web API(fetch / Request / Response)
├── TypedArray / TextEncoder / Web Crypto API
├── ❌ 无 fs、无 Node net 模块、受限 npm 包
├── 冷启动:< 5ms
└── 执行限制:30s 默认(可配置到 60s)
1.2 对比总表
| 维度 | Node.js Runtime | Edge Runtime |
|---|---|---|
| 底层引擎 | Node.js 完整容器 | V8 Isolate(Chrome 同款引擎) |
| 启动时间 | 50-500ms 冷启动 | < 5ms 冷启动 |
| 内存限制 | 1024MB / 3008MB(取决于区域) | 128MB |
| 执行时间上限 | 10s / 60s | 30s / 60s(可配置) |
| 文件系统(fs) | ✅ 完整支持 | ❌ 不可用 |
| TCP 连接(Postgres) | ✅ 直接连接 | ❌ 需通过 HTTP 代理(如 Prisma Accelerate) |
| Node.js 内置模块 | ✅ 全部 | ⚠️ 有限子集(util、buffer 等部分可用) |
| npm 生态 | ✅ 99% 可用 | ⚠️ 仅纯 JS / Web API 兼容包 |
| Web API | ❌ 需要 polyfill | ✅ fetch / Request / Response / Headers / URL 原生支持 |
| 流式响应(Streaming) | ✅ 支持 | ✅ 天然设计支持,体验更优 |
| 全球部署 | 按区域(us-east-1 等) | 全网点(Anycast) |
| 适用场景 | 数据库操作、文件处理、复杂后端逻辑 | 路由、认证、流式 AI、轻量 API、边缘聚合 |
1.3 什么时候选什么?
需要做数据库操作?
├── 是 → 需要 Prisma/Postgres 直连?
│ ├── 是 → Node.js Runtime(Serverless Functions)
│ └── 否(可用 HTTP API)→ Edge Runtime ✅
└── 否 → 请求延迟敏感?(如 AI 流式输出)
├── 是 → Edge Runtime ✅
└── 否(批量处理、定时任务)→ Node.js Runtime
结论:大部分场景可以混合使用——页面渲染/数据库操作走 Node.js,中间件/轻量 API/流式响应走 Edge。
二、Next.js 中声明 Edge Runtime
2.1 Route Handler(API 路由)
// app/api/stream/route.ts
// 顶部声明 runtime
export const runtime = 'edge';
export async function GET(request: Request) {
const encoder = new TextEncoder();
const stream = new ReadableStream({
start(controller) {
let count = 0;
const interval = setInterval(() => {
controller.enqueue(encoder.encode(`data: Message ${++count}\n\n`));
if (count >= 5) {
clearInterval(interval);
controller.close();
}
}, 1000);
},
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
}
2.2 页面级别
// app/dashboard/page.tsx
export const runtime = 'edge'; // SSR 页面在 Edge 渲染
export default async function DashboardPage() {
// Edge Runtime 下不能直连 Postgres
// 但可以通过外部 API 获取数据
const data = await fetch('https://api.example.com/stats').then(r => r.json());
return (
<main>
<h1>Dashboard</h1>
<p>{data.totalUsers} users</p>
</main>
);
}
2.3 Middleware(天然 Edge)
Next.js Middleware 在 Vercel 上始终运行在 Edge Runtime(不能选择 Node.js):
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Edge Runtime 执行:低延迟、全球节点
const country = request.geo?.country || 'US';
// A/B 测试:按国家路由到不同页面
if (country === 'CN' && request.nextUrl.pathname === '/') {
return NextResponse.rewrite(new URL('/cn-home', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
三、流式响应(Streaming):AI 场景核心能力
3.1 OpenAI SDK 流式示例
// app/api/chat/route.ts
export const runtime = 'edge';
export async function POST(request: Request) {
const { messages } = await request.json();
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: 'gpt-4',
stream: true,
messages,
}),
});
// 直接透传 OpenAI 的 SSE 流
return new Response(response.body, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
},
});
}
前端消费 SSE:
// lib/chat.ts
export async function* streamChat(messages: any[]) {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages }),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// 解析 SSE 格式:data: {...}\n\n
for (const line of chunk.split('\n')) {
if (line.startsWith('data: ')) {
const json = line.slice(6);
if (json === '[DONE]') return;
try {
yield JSON.parse(json);
} catch { /* 偶现的 JSON 片段 */ }
}
}
}
}
3.2 Vercel AI SDK 方式(推荐)
npm install ai openai
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export const runtime = 'edge';
export async function POST(request: Request) {
const { messages } = await request.json();
const result = streamText({
model: openai('gpt-4'), // 或 'gpt-3.5-turbo'
messages,
maxTokens: 1024,
});
return result.toDataStreamResponse();
}
前端配合 useChat hook(Vercel AI SDK 提供):
// app/page.tsx
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button>Send</button>
</form>
</div>
);
}
Edge Functions 做流式的优势:
- 用户请求被路由到最近边缘节点 → 到 OpenAI API 的延迟最小化
- 流式返回时,Edge 层持续保持连接,不像 Serverless 有硬超时
- 全球用户都能获得低延迟的 “打字机” 效果
四、地理位置与个性化
4.1 获取用户地理位置
Edge Functions 可以读取请求来源的地理信息:
// app/api/geo/route.ts
export const runtime = 'edge';
export function GET(request: Request) {
// request.geo 仅在 Next.js Middleware 和 Edge Functions 中可用
// 在独立 Edge Functions 中,使用 cf-connecting-ip 和 Cloudflare 的 GeoIP
const country = request.headers.get('cf-ipcountry') || request.headers.get('x-vercel-ip-country') || 'unknown';
const city = request.headers.get('x-vercel-ip-city') || 'unknown';
const region = request.headers.get('x-vercel-ip-country-region') || 'unknown';
const latitude = request.headers.get('x-vercel-ip-latitude');
const longitude = request.headers.get('x-vercel-ip-longitude');
return Response.json({
country,
city,
region,
location: latitude && longitude ? { lat: latitude, lng: longitude } : null,
});
}
可用的请求头(Vercel Edge):
| Header | 说明 |
|---|---|
x-vercel-ip-country | ISO 3166-1 alpha-2 国家代码 |
x-vercel-ip-country-region | 州/省代码 |
x-vercel-ip-city | 城市名(英文) |
x-vercel-ip-latitude | 纬度 |
x-vercel-ip-longitude | 经度 |
x-vercel-ip-timezone | 时区 |
4.2 多语言路由
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
const locales = ['en', 'zh', 'ja'];
const defaultLocale = 'en';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 检查路径已有语言前缀
const pathnameHasLocale = locales.some(
locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);
if (pathnameHasLocale) return NextResponse.next();
// 根据用户国家判断语言
const country = request.geo?.country || 'US';
const locale =
country === 'CN' || country === 'TW' || country === 'HK' ? 'zh' :
country === 'JP' ? 'ja' :
defaultLocale;
request.nextUrl.pathname = `/${locale}${pathname}`;
return NextResponse.redirect(request.nextUrl);
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
五、身份验证与访问控制
5.1 JWT 验证(Edge 兼容)
// lib/auth-edge.ts
import { SignJWT, jwtVerify } from 'jose';
const secret = new TextEncoder().encode(process.env.JWT_SECRET!);
export async function verifyToken(token: string) {
try {
const { payload } = await jwtVerify(token, secret, { clockTolerance: 60 });
return payload;
} catch {
return null;
}
}
⚠️
jsonwebtoken包依赖 Node.js 的crypto模块,在 Edge Runtime 不可用。使用jose包,它基于 Web Crypto API。
5.2 Edge Middleware 做认证拦截
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { verifyToken } from './lib/auth-edge';
const publicPaths = ['/login', '/register', '/api/auth'];
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
if (publicPaths.some(p => pathname.startsWith(p))) {
return NextResponse.next();
}
const token = request.cookies.get('token')?.value;
const payload = token ? await verifyToken(token) : null;
if (!payload) {
return NextResponse.redirect(new URL('/login', request.url));
}
// 把用户信息注入请求头(下游页面/API 可用)
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-id', payload.sub as string);
requestHeaders.set('x-user-role', payload.role as string);
return NextResponse.next({
request: { headers: requestHeaders },
});
}
六、性能优化
6.1 减少冷启动
Edge Functions 冷启动已极低(< 5ms),但仍有优化空间:
// 避免在全局作用域做重计算
// ❌ 不推荐
const heavyData = JSON.parse(
fs.readFileSync('./data.json', 'utf8') // Edge 不能这么做
);
// ✅ 推荐:延迟加载
const getData = () => {
if (!globalThis.__data) {
globalThis.__data = fetch('https://cdn.example.com/data.json').then(r => r.json());
}
return globalThis.__data;
};
export default async function handler(request: Request) {
const data = await getData();
return Response.json(data);
}
6.2 缓存策略
Edge Functions 可以设置 CDN 缓存头,减少重复执行:
export const runtime = 'edge';
export async function GET() {
const data = await fetchSomeData();
return Response.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=86400',
},
});
}
s-maxage=300:CDN 缓存 5 分钟stale-while-revalidate=86400:缓存过期后,旧数据继续服务,后台异步更新
6.3 Bundle 大小优化
Edge Functions 的 Bundle 越小,启动越快:
# 分析 Edge Functions 的 Bundle 大小
npm install -D @vercel/nft
# 或查看 Vercel Dashboard → Network → 查看 Functions 的 Compressed Size
优化建议:
- 避免引入整个 lodash(用
lodash-es的按需导入) - 用
jose替代jsonwebtoken - 用原生
fetch替代axios - 移除未使用的依赖
七、Vanilla Edge Functions(非 Next.js)
如果你不用 Next.js,Vercel 也支持独立的 Edge Functions:
// api/hello.ts
export const config = {
runtime: 'edge',
};
export default async function handler(request: Request) {
return new Response('Hello from Edge!', {
status: 200,
headers: { 'Content-Type': 'text/plain' },
});
}
// api/uppercase.ts
export const config = { runtime: 'edge' };
export default async function handler(request: Request) {
const { text } = await request.json();
return Response.json({ result: text.toUpperCase() });
}
八、常见问题(FAQ)
Edge Runtime 能连 Redis 吗?
不能直连 TCP。Redis 协议基于 TCP,Edge Runtime 不支持原生 TCP Socket。解决方法:
- 使用 Redis HTTP API(如 Upstash Redis 提供的 REST API)
- 使用 Durable Objects / KV(Cloudflare 生态)
- 把缓存逻辑放到 Node.js Serverless Functions 中
Edge Functions 和 Vercel Middleware 有什么区别?
- Middleware:请求过滤层,决定"要不要继续处理这个请求",可修改请求头、重定向、重写 URL
- Edge Functions:独立 API 端点或页面渲染,执行业务逻辑,返回响应
- 关系:Middleware 执行在前,Edge Functions 执行在后。一个请求可能先经过 Middleware,再到达 Edge Function。
为什么我的 Edge Function 提示 “Module not found”?
因为 Edge Runtime 只支持纯 JavaScript / Web API 兼容的 npm 包。检查:
- 是否有包依赖 Node.js 原生模块(fs、net、child_process)
- 是否使用了
jsonwebtoken(改用jose) - 是否使用了 Prisma 直连(改用 Prisma Accelerate)
Edge Functions 在国内表现如何?
Edge Functions 的部署节点分布在日本、新加坡、香港等地,对中国大陆用户的延迟约 50-100ms。如果需要更低延迟,建议:
- 配合 Cloudflare Proxy(将域名 DNS 托管到 Cloudflare)
- 考虑 Cloudflare Workers(在中国大陆有更多 PoP 节点)
相关阅读
- Vercel 详解:前端与 AI 应用的一站式云平台
- Vercel Middleware 实战指南
- Vercel AI SDK 指南
- Vercel 国内访问优化指南
- Vercel 定价与成本详解
- Vercel 专题导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。