Edge Functions #
Edge Functions 概述 #
Edge Functions 是在 Vercel 边缘网络上运行的函数:
text
┌──────────────────────────────────────────────────────┐
│ │
│ 传统服务器架构 │
│ 用户 ──────────────────▶ 中央服务器 │
│ (距离远,延迟高) │
│ │
│ 边缘计算架构 │
│ 用户 ───▶ 最近的边缘节点 ───▶ 执行函数 │
│ (就近访问,低延迟) │
│ │
└──────────────────────────────────────────────────────┘
Edge vs Serverless #
| 特性 | Edge Functions | Serverless Functions |
|---|---|---|
| 启动时间 | 毫秒级 | 秒级(冷启动) |
| 执行位置 | 边缘节点 | 特定区域 |
| 延迟 | 极低 | 较低 |
| 运行时 | V8/Edge Runtime | Node.js |
| 执行时间限制 | 30秒 | 60秒+ |
| 包大小 | 1MB | 50MB |
Edge Runtime #
运行时限制 #
text
┌─────────────────────────────────────────┐
│ Edge Runtime 限制 │
├─────────────────────────────────────────┤
│ 执行时间 → 30 秒 │
│ 内存 → 128 MB │
│ 代码大小 → 1 MB │
│ 请求体大小 → 4 MB │
└─────────────────────────────────────────┘
支持的 API #
text
Web 标准 API:
├── fetch
├── Request / Response
├── Headers
├── URL / URLSearchParams
├── Crypto
├── TextEncoder / TextDecoder
└── setTimeout / setInterval
不支持的 API #
text
Node.js 特有 API:
├── fs
├── path
├── crypto (Node.js 版本)
├── buffer
└── process
创建 Edge Function #
Next.js API Route #
typescript
import { NextRequest, NextResponse } from 'next/server'
export const runtime = 'edge'
export async function GET(request: NextRequest) {
return NextResponse.json({
message: 'Hello from Edge!',
geo: request.geo,
})
}
文件位置 #
text
app/
└── api/
└── hello/
└── route.ts
独立 Edge Function #
typescript
export const config = {
runtime: 'edge',
}
export default async function handler(request: Request) {
return new Response('Hello from Edge!', {
headers: {
'content-type': 'text/plain',
},
})
}
中间件 #
创建中间件 #
typescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('x-custom-header', 'value')
return response
}
export const config = {
matcher: '/api/:path*',
}
中间件位置 #
text
项目根目录/
└── middleware.ts
匹配路径 #
typescript
export const config = {
matcher: [
'/api/:path*',
'/admin/:path*',
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
地理路由 #
获取地理位置 #
typescript
import { NextRequest, NextResponse } from 'next/server'
export const runtime = 'edge'
export async function GET(request: NextRequest) {
const geo = request.geo
return NextResponse.json({
city: geo?.city,
country: geo?.country,
region: geo?.region,
latitude: geo?.latitude,
longitude: geo?.longitude,
})
}
地理位置字段 #
| 字段 | 说明 | 示例 |
|---|---|---|
city |
城市 | “San Francisco” |
country |
国家代码 | “US” |
region |
地区代码 | “CA” |
latitude |
纬度 | “37.7749” |
longitude |
经度 | “-122.4194” |
基于地理位置的重定向 #
typescript
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
const country = request.geo?.country || 'US'
if (country === 'CN') {
return NextResponse.redirect(new URL('/cn', request.url))
}
if (country === 'JP') {
return NextResponse.redirect(new URL('/jp', request.url))
}
return NextResponse.next()
}
A/B 测试 #
简单 A/B 测试 #
typescript
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
const variant = Math.random() > 0.5 ? 'A' : 'B'
const response = NextResponse.next()
response.headers.set('x-variant', variant)
return response
}
持久化变体 #
typescript
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
let variant = request.cookies.get('variant')?.value
if (!variant) {
variant = Math.random() > 0.5 ? 'A' : 'B'
}
const response = NextResponse.next()
response.cookies.set('variant', variant, { maxAge: 60 * 60 * 24 * 30 })
return response
}
身份验证 #
JWT 验证 #
typescript
import { NextRequest, NextResponse } from 'next/server'
import { jwtVerify } from 'jose'
export async function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
try {
const secret = new TextEncoder().encode(process.env.JWT_SECRET)
await jwtVerify(token, secret)
return NextResponse.next()
} catch {
return NextResponse.redirect(new URL('/login', request.url))
}
}
export const config = {
matcher: '/dashboard/:path*',
}
基本认证 #
typescript
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
const authHeader = request.headers.get('authorization')
if (!authHeader) {
return new NextResponse('Authentication required', {
status: 401,
headers: {
'WWW-Authenticate': 'Basic realm="Secure Area"',
},
})
}
const [username, password] = atob(authHeader.split(' ')[1]).split(':')
if (username !== 'admin' || password !== 'secret') {
return new NextResponse('Invalid credentials', { status: 401 })
}
return NextResponse.next()
}
缓存控制 #
边缘缓存 #
typescript
import { NextResponse } from 'next/server'
export const runtime = 'edge'
export async function GET() {
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache',
}).then(res => res.json())
return NextResponse.json(data, {
headers: {
'Cache-Control': 'public, max-age=3600, s-maxage=3600',
},
})
}
动态响应 #
typescript
import { NextResponse } from 'next/server'
export const runtime = 'edge'
export async function GET() {
return NextResponse.json(
{ time: new Date().toISOString() },
{
headers: {
'Cache-Control': 'no-store',
},
}
)
}
请求处理 #
读取请求体 #
typescript
export const runtime = 'edge'
export async function POST(request: Request) {
const body = await request.json()
return Response.json({ received: body })
}
读取表单数据 #
typescript
export const runtime = 'edge'
export async function POST(request: Request) {
const formData = await request.formData()
const name = formData.get('name')
const file = formData.get('file')
return Response.json({ name, file: file?.name })
}
流式响应 #
typescript
export const runtime = 'edge'
export async function GET() {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(encoder.encode(`data: ${i}\n\n`))
await new Promise(resolve => setTimeout(resolve, 1000))
}
controller.close()
},
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
},
})
}
配置选项 #
vercel.json 配置 #
json
{
"functions": {
"app/api/**/*.ts": {
"runtime": "edge"
}
}
}
区域配置 #
json
{
"functions": {
"app/api/**/*.ts": {
"runtime": "edge",
"regions": ["hkg1", "sfo1"]
}
}
}
调试 #
本地调试 #
bash
vercel dev
日志输出 #
typescript
export const runtime = 'edge'
export async function GET() {
console.log('Edge function executed')
return Response.json({ status: 'ok' })
}
查看日志 #
bash
vercel logs --follow
最佳实践 #
性能优化 #
text
┌─────────────────────────────────────────┐
│ Edge Functions 最佳实践 │
├─────────────────────────────────────────┤
│ ✓ 保持代码精简 │
│ ✓ 避免大型依赖 │
│ ✓ 使用缓存减少请求 │
│ ✓ 合理设置超时 │
│ ✓ 处理错误情况 │
└─────────────────────────────────────────┘
错误处理 #
typescript
export const runtime = 'edge'
export async function GET() {
try {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error('API request failed')
}
const data = await response.json()
return Response.json(data)
} catch (error) {
return Response.json(
{ error: 'Internal Server Error' },
{ status: 500 }
)
}
}
下一步 #
了解 Edge Functions 后,接下来学习 Serverless Functions 探索更多后端能力!
最后更新:2026-03-28