边缘计算与前端优化
边缘计算正在重新定义前端应用的架构和性能边界。通过将计算和数据存储更靠近用户,我们可以显著提升应用的响应速度和用户体验。本文将深入探讨边缘计算在前端领域的应用和最佳实践。
🌐 边缘计算概述
什么是边缘计算
边缘计算是一种分布式计算架构,将数据处理和存储从中心化的云服务器转移到更接近数据源和用户的"边缘"节点。
核心优势:
- 低延迟:减少数据传输距离
- 高可用性:分布式架构提供冗余
- 带宽优化:减少核心网络负载
- 数据本地化:满足数据主权要求
边缘计算架构
mermaid
graph TD
A[用户] --> B[边缘节点]
B --> C[区域数据中心]
C --> D[中心云服务]
B --> E[边缘缓存]
B --> F[边缘计算]
B --> G[边缘存储]
H[CDN] --> B
I[Edge Functions] --> B
J[Edge Database] --> B
🚀 边缘计算平台
Cloudflare Workers
Cloudflare Workers 提供了强大的边缘计算能力:
javascript
// Cloudflare Worker 示例
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
// 地理位置优化
const country = request.cf.country
const region = getRegionByCountry(country)
// 边缘缓存策略
const cacheKey = `${url.pathname}-${region}`
const cache = caches.default
let response = await cache.match(cacheKey)
if (!response) {
// 动态内容生成
response = await generateResponse(request, region)
// 设置缓存头
response.headers.set('Cache-Control', 'public, max-age=3600')
response.headers.set('CDN-Cache-Control', 'public, max-age=86400')
// 存储到边缘缓存
ctx.waitUntil(cache.put(cacheKey, response.clone()))
}
return response
}
}
// 根据地区生成个性化内容
async function generateResponse(request, region) {
const config = await getRegionConfig(region)
const html = `
<!DOCTYPE html>
<html>
<head>
<title>欢迎来到 ${config.regionName}</title>
<meta charset="utf-8">
</head>
<body>
<h1>您好,${config.greeting}!</h1>
<p>当前时间:${new Date().toLocaleString(config.locale)}</p>
<p>推荐服务器:${config.recommendedServer}</p>
<script>
// 注入地区特定的配置
window.REGION_CONFIG = ${JSON.stringify(config)};
// 性能监控
performance.mark('edge-response-start');
</script>
</body>
</html>
`
return new Response(html, {
headers: {
'Content-Type': 'text/html;charset=UTF-8',
'X-Edge-Region': region,
'X-Response-Time': Date.now()
}
})
}
// 地区配置
async function getRegionConfig(region) {
const configs = {
'asia': {
regionName: '亚洲',
greeting: '您好',
locale: 'zh-CN',
recommendedServer: 'asia-east1',
currency: 'CNY',
timezone: 'Asia/Shanghai'
},
'europe': {
regionName: 'Europe',
greeting: 'Hello',
locale: 'en-GB',
recommendedServer: 'europe-west1',
currency: 'EUR',
timezone: 'Europe/London'
},
'americas': {
regionName: 'Americas',
greeting: 'Hello',
locale: 'en-US',
recommendedServer: 'us-central1',
currency: 'USD',
timezone: 'America/New_York'
}
}
return configs[region] || configs['americas']
}
function getRegionByCountry(country) {
const asianCountries = ['CN', 'JP', 'KR', 'SG', 'HK', 'TW']
const europeanCountries = ['GB', 'DE', 'FR', 'IT', 'ES', 'NL']
if (asianCountries.includes(country)) return 'asia'
if (europeanCountries.includes(country)) return 'europe'
return 'americas'
}
Vercel Edge Functions
javascript
// pages/api/edge/personalize.js
export const config = {
runtime: 'edge',
}
export default async function handler(request) {
const { geo, ip } = request
// 获取用户地理信息
const userLocation = {
country: geo.country,
region: geo.region,
city: geo.city,
latitude: geo.latitude,
longitude: geo.longitude
}
// 基于位置的内容个性化
const personalizedContent = await getPersonalizedContent(userLocation)
// A/B 测试
const variant = getABTestVariant(ip)
return new Response(JSON.stringify({
content: personalizedContent,
variant: variant,
location: userLocation,
timestamp: new Date().toISOString(),
edge: process.env.VERCEL_REGION
}), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300'
}
})
}
async function getPersonalizedContent(location) {
// 根据地理位置返回个性化内容
const weatherAPI = `https://api.weather.com/current?lat=${location.latitude}&lon=${location.longitude}`
try {
const weather = await fetch(weatherAPI).then(res => res.json())
return {
greeting: getLocalizedGreeting(location.country),
weather: weather.current,
localTime: new Date().toLocaleString('en-US', {
timeZone: getTimezoneByCountry(location.country)
}),
recommendations: getLocalRecommendations(location.country)
}
} catch (error) {
return {
greeting: 'Hello!',
error: 'Unable to fetch personalized content'
}
}
}
function getABTestVariant(ip) {
// 基于 IP 的简单哈希来确定 A/B 测试变体
const hash = ip.split('.').reduce((acc, octet) => acc + parseInt(octet), 0)
return hash % 2 === 0 ? 'A' : 'B'
}
📊 边缘缓存策略
智能缓存管理
javascript
// 边缘缓存管理器
class EdgeCacheManager {
constructor(options = {}) {
this.defaultTTL = options.defaultTTL || 3600
this.maxAge = options.maxAge || 86400
this.staleWhileRevalidate = options.staleWhileRevalidate || 300
}
// 生成缓存键
generateCacheKey(request, factors = {}) {
const url = new URL(request.url)
const baseKey = `${url.pathname}${url.search}`
// 添加变化因子
const variations = []
if (factors.country) variations.push(`country:${factors.country}`)
if (factors.device) variations.push(`device:${factors.device}`)
if (factors.language) variations.push(`lang:${factors.language}`)
if (factors.userType) variations.push(`user:${factors.userType}`)
return variations.length > 0
? `${baseKey}|${variations.join('|')}`
: baseKey
}
// 设置缓存策略
setCacheHeaders(response, strategy = 'default') {
const strategies = {
'static': {
'Cache-Control': 'public, max-age=31536000, immutable',
'CDN-Cache-Control': 'public, max-age=31536000'
},
'dynamic': {
'Cache-Control': `public, max-age=${this.defaultTTL}, stale-while-revalidate=${this.staleWhileRevalidate}`,
'CDN-Cache-Control': `public, max-age=${this.maxAge}`
},
'personalized': {
'Cache-Control': 'private, max-age=300',
'CDN-Cache-Control': 'public, max-age=60'
},
'api': {
'Cache-Control': 'public, max-age=60, stale-while-revalidate=300',
'CDN-Cache-Control': 'public, max-age=300'
}
}
const headers = strategies[strategy] || strategies['default']
Object.entries(headers).forEach(([key, value]) => {
response.headers.set(key, value)
})
return response
}
// 缓存失效
async invalidateCache(patterns) {
// 实现缓存失效逻辑
for (const pattern of patterns) {
await this.purgeByPattern(pattern)
}
}
async purgeByPattern(pattern) {
// 根据模式清除缓存
// 这里需要根据具体的 CDN 提供商实现
console.log(`Purging cache for pattern: ${pattern}`)
}
}
// 使用示例
const cacheManager = new EdgeCacheManager({
defaultTTL: 1800,
maxAge: 7200,
staleWhileRevalidate: 600
})
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
// 确定内容类型
const contentType = getContentType(url.pathname)
// 生成缓存键
const cacheKey = cacheManager.generateCacheKey(request, {
country: request.cf.country,
device: getDeviceType(request.headers.get('User-Agent')),
language: getPreferredLanguage(request.headers.get('Accept-Language'))
})
// 检查缓存
const cache = caches.default
let response = await cache.match(cacheKey)
if (!response) {
// 生成新响应
response = await generateResponse(request)
// 设置缓存策略
response = cacheManager.setCacheHeaders(response, contentType)
// 存储到缓存
ctx.waitUntil(cache.put(cacheKey, response.clone()))
}
return response
}
}
预测性缓存
javascript
// 预测性缓存系统
class PredictiveCacheSystem {
constructor() {
this.userBehaviorData = new Map()
this.popularContent = new Set()
this.prefetchQueue = []
}
// 分析用户行为
analyzeUserBehavior(userId, action, resource) {
if (!this.userBehaviorData.has(userId)) {
this.userBehaviorData.set(userId, {
visitedPages: [],
preferences: {},
patterns: []
})
}
const userData = this.userBehaviorData.get(userId)
userData.visitedPages.push({
resource,
timestamp: Date.now(),
action
})
// 识别访问模式
this.identifyPatterns(userId)
}
// 识别访问模式
identifyPatterns(userId) {
const userData = this.userBehaviorData.get(userId)
const recentVisits = userData.visitedPages.slice(-10)
// 查找常见的访问序列
const sequences = this.findCommonSequences(recentVisits)
userData.patterns = sequences
// 预测下一个可能访问的资源
const predictions = this.predictNextResources(sequences)
// 添加到预取队列
predictions.forEach(resource => {
this.addToPrefetchQueue(resource, userId)
})
}
// 查找常见序列
findCommonSequences(visits) {
const sequences = []
for (let i = 0; i < visits.length - 1; i++) {
const current = visits[i].resource
const next = visits[i + 1].resource
sequences.push([current, next])
}
return sequences
}
// 预测下一个资源
predictNextResources(patterns) {
const predictions = new Map()
patterns.forEach(([current, next]) => {
if (!predictions.has(current)) {
predictions.set(current, new Map())
}
const nextMap = predictions.get(current)
nextMap.set(next, (nextMap.get(next) || 0) + 1)
})
// 返回概率最高的预测
const results = []
predictions.forEach((nextMap, current) => {
const sorted = [...nextMap.entries()].sort((a, b) => b[1] - a[1])
if (sorted.length > 0 && sorted[0][1] > 1) {
results.push(sorted[0][0])
}
})
return results
}
// 添加到预取队列
addToPrefetchQueue(resource, userId) {
this.prefetchQueue.push({
resource,
userId,
priority: this.calculatePriority(resource, userId),
timestamp: Date.now()
})
// 按优先级排序
this.prefetchQueue.sort((a, b) => b.priority - a.priority)
}
// 计算预取优先级
calculatePriority(resource, userId) {
let priority = 1
// 基于用户历史行为
const userData = this.userBehaviorData.get(userId)
if (userData) {
const visitCount = userData.visitedPages.filter(
visit => visit.resource === resource
).length
priority += visitCount * 0.5
}
// 基于全局热度
if (this.popularContent.has(resource)) {
priority += 2
}
return priority
}
// 执行预取
async executePrefetch(maxConcurrent = 3) {
const batch = this.prefetchQueue.splice(0, maxConcurrent)
const prefetchPromises = batch.map(async (item) => {
try {
const response = await fetch(item.resource, {
method: 'GET',
headers: {
'X-Prefetch': 'true',
'X-User-ID': item.userId
}
})
if (response.ok) {
console.log(`Prefetched: ${item.resource}`)
}
} catch (error) {
console.error(`Prefetch failed for ${item.resource}:`, error)
}
})
await Promise.allSettled(prefetchPromises)
}
}
// 集成到边缘函数
const predictiveCache = new PredictiveCacheSystem()
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
const userId = request.headers.get('X-User-ID') || 'anonymous'
// 记录用户行为
predictiveCache.analyzeUserBehavior(userId, 'visit', url.pathname)
// 异步执行预取
ctx.waitUntil(predictiveCache.executePrefetch())
// 正常处理请求
return await handleRequest(request)
}
}
🔄 边缘数据同步
分布式状态管理
javascript
// 边缘状态同步器
class EdgeStateSync {
constructor(options = {}) {
this.region = options.region || 'unknown'
this.syncInterval = options.syncInterval || 30000
this.conflictResolution = options.conflictResolution || 'last-write-wins'
this.pendingUpdates = new Map()
this.lastSyncTimestamp = 0
}
// 更新本地状态
async updateLocalState(key, value, metadata = {}) {
const update = {
key,
value,
timestamp: Date.now(),
region: this.region,
version: this.generateVersion(),
metadata
}
// 存储到本地边缘存储
await this.storeLocally(key, update)
// 添加到待同步队列
this.pendingUpdates.set(key, update)
// 触发同步
this.scheduleSyncIfNeeded()
return update
}
// 同步到其他边缘节点
async syncToOtherRegions() {
if (this.pendingUpdates.size === 0) return
const updates = Array.from(this.pendingUpdates.values())
this.pendingUpdates.clear()
try {
// 发送到中央协调器
await this.sendToCoordinator(updates)
// 直接同步到其他边缘节点
await this.syncToEdgeNodes(updates)
this.lastSyncTimestamp = Date.now()
} catch (error) {
console.error('Sync failed:', error)
// 重新添加到待同步队列
updates.forEach(update => {
this.pendingUpdates.set(update.key, update)
})
}
}
// 处理来自其他节点的更新
async handleRemoteUpdate(remoteUpdate) {
const localUpdate = await this.getLocalState(remoteUpdate.key)
if (!localUpdate) {
// 本地没有数据,直接应用
await this.applyUpdate(remoteUpdate)
return
}
// 冲突解决
const resolvedUpdate = await this.resolveConflict(localUpdate, remoteUpdate)
if (resolvedUpdate !== localUpdate) {
await this.applyUpdate(resolvedUpdate)
}
}
// 冲突解决策略
async resolveConflict(localUpdate, remoteUpdate) {
switch (this.conflictResolution) {
case 'last-write-wins':
return localUpdate.timestamp > remoteUpdate.timestamp
? localUpdate
: remoteUpdate
case 'version-vector':
return this.resolveByVersionVector(localUpdate, remoteUpdate)
case 'custom':
return await this.customConflictResolution(localUpdate, remoteUpdate)
default:
return remoteUpdate
}
}
// 版本向量冲突解决
resolveByVersionVector(localUpdate, remoteUpdate) {
const localVersion = localUpdate.version
const remoteVersion = remoteUpdate.version
// 比较版本向量
const localNewer = this.isVersionNewer(localVersion, remoteVersion)
const remoteNewer = this.isVersionNewer(remoteVersion, localVersion)
if (localNewer && !remoteNewer) {
return localUpdate
} else if (remoteNewer && !localNewer) {
return remoteUpdate
} else {
// 并发更新,需要合并
return this.mergeUpdates(localUpdate, remoteUpdate)
}
}
// 合并并发更新
mergeUpdates(update1, update2) {
// 实现具体的合并逻辑
return {
...update1,
value: this.mergeValues(update1.value, update2.value),
timestamp: Math.max(update1.timestamp, update2.timestamp),
version: this.mergeVersions(update1.version, update2.version)
}
}
// 生成版本号
generateVersion() {
return {
[this.region]: Date.now(),
counter: Math.random().toString(36).substr(2, 9)
}
}
// 本地存储
async storeLocally(key, update) {
// 使用 KV 存储或其他边缘存储
await env.EDGE_KV.put(key, JSON.stringify(update))
}
// 获取本地状态
async getLocalState(key) {
const stored = await env.EDGE_KV.get(key)
return stored ? JSON.parse(stored) : null
}
// 发送到协调器
async sendToCoordinator(updates) {
const response = await fetch('https://coordinator.example.com/sync', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Region': this.region
},
body: JSON.stringify({
updates,
region: this.region,
timestamp: Date.now()
})
})
if (!response.ok) {
throw new Error(`Coordinator sync failed: ${response.statusText}`)
}
}
// 同步到其他边缘节点
async syncToEdgeNodes(updates) {
const otherRegions = ['us-east', 'eu-west', 'asia-pacific']
.filter(region => region !== this.region)
const syncPromises = otherRegions.map(region =>
this.syncToRegion(region, updates)
)
await Promise.allSettled(syncPromises)
}
async syncToRegion(region, updates) {
try {
const response = await fetch(`https://${region}.edge.example.com/sync`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Source-Region': this.region
},
body: JSON.stringify(updates)
})
if (!response.ok) {
throw new Error(`Sync to ${region} failed: ${response.statusText}`)
}
} catch (error) {
console.error(`Failed to sync to ${region}:`, error)
}
}
// 调度同步
scheduleSyncIfNeeded() {
const timeSinceLastSync = Date.now() - this.lastSyncTimestamp
if (timeSinceLastSync > this.syncInterval) {
// 立即同步
setTimeout(() => this.syncToOtherRegions(), 0)
}
}
}
// 使用示例
const stateSync = new EdgeStateSync({
region: 'asia-east',
syncInterval: 15000,
conflictResolution: 'version-vector'
})
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
if (request.method === 'POST' && url.pathname === '/api/update') {
const { key, value } = await request.json()
// 更新边缘状态
const update = await stateSync.updateLocalState(key, value)
return new Response(JSON.stringify({
success: true,
update
}), {
headers: { 'Content-Type': 'application/json' }
})
}
if (request.method === 'POST' && url.pathname === '/sync') {
const updates = await request.json()
// 处理来自其他节点的同步
for (const update of updates) {
await stateSync.handleRemoteUpdate(update)
}
return new Response('OK')
}
return new Response('Not Found', { status: 404 })
}
}
📱 移动端优化
自适应内容交付
javascript
// 移动端优化的边缘函数
class MobileOptimizer {
constructor() {
this.deviceProfiles = {
'mobile-low': {
imageQuality: 60,
imageFormat: 'webp',
maxImageWidth: 480,
enableLazyLoading: true,
minifyCSS: true,
minifyJS: true,
enableGzip: true
},
'mobile-high': {
imageQuality: 75,
imageFormat: 'webp',
maxImageWidth: 768,
enableLazyLoading: true,
minifyCSS: true,
minifyJS: true,
enableGzip: true
},
'tablet': {
imageQuality: 80,
imageFormat: 'webp',
maxImageWidth: 1024,
enableLazyLoading: false,
minifyCSS: false,
minifyJS: true,
enableGzip: true
},
'desktop': {
imageQuality: 90,
imageFormat: 'webp',
maxImageWidth: 1920,
enableLazyLoading: false,
minifyCSS: false,
minifyJS: false,
enableGzip: true
}
}
}
// 检测设备类型
detectDevice(userAgent, viewport) {
const isMobile = /Mobile|Android|iPhone|iPad/.test(userAgent)
const isTablet = /iPad|Tablet/.test(userAgent)
if (isMobile && !isTablet) {
return viewport && viewport.width < 480 ? 'mobile-low' : 'mobile-high'
} else if (isTablet) {
return 'tablet'
} else {
return 'desktop'
}
}
// 优化图片
async optimizeImage(imageUrl, deviceProfile, request) {
const optimizedUrl = new URL('https://images.example.com/optimize')
optimizedUrl.searchParams.set('url', imageUrl)
optimizedUrl.searchParams.set('quality', deviceProfile.imageQuality)
optimizedUrl.searchParams.set('format', deviceProfile.imageFormat)
optimizedUrl.searchParams.set('width', deviceProfile.maxImageWidth)
// 检查客户端支持的格式
const acceptHeader = request.headers.get('Accept') || ''
if (acceptHeader.includes('image/avif')) {
optimizedUrl.searchParams.set('format', 'avif')
} else if (acceptHeader.includes('image/webp')) {
optimizedUrl.searchParams.set('format', 'webp')
}
return optimizedUrl.toString()
}
// 优化 HTML 内容
optimizeHTML(html, deviceProfile) {
let optimizedHTML = html
// 图片懒加载
if (deviceProfile.enableLazyLoading) {
optimizedHTML = optimizedHTML.replace(
/<img([^>]+)src="([^"]+)"([^>]*)>/g,
'<img$1data-src="$2" src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 1 1\'%3E%3C/svg%3E" loading="lazy"$3>'
)
// 添加懒加载脚本
optimizedHTML += `
<script>
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
</script>
`
}
// CSS 压缩
if (deviceProfile.minifyCSS) {
optimizedHTML = optimizedHTML.replace(
/<style[^>]*>([\s\S]*?)<\/style>/g,
(match, css) => {
const minifiedCSS = css
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\s+/g, ' ')
.trim()
return `<style>${minifiedCSS}</style>`
}
)
}
// 移除不必要的空白
optimizedHTML = optimizedHTML
.replace(/>\s+</g, '><')
.replace(/\s+/g, ' ')
.trim()
return optimizedHTML
}
// 网络感知优化
applyNetworkOptimizations(response, connectionType) {
const headers = new Headers(response.headers)
switch (connectionType) {
case 'slow-2g':
case '2g':
// 极度压缩
headers.set('Content-Encoding', 'br')
headers.set('X-Optimization-Level', 'maximum')
break
case '3g':
// 中等压缩
headers.set('Content-Encoding', 'gzip')
headers.set('X-Optimization-Level', 'medium')
break
case '4g':
case '5g':
default:
// 标准优化
headers.set('X-Optimization-Level', 'standard')
break
}
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers
})
}
}
// 使用示例
const mobileOptimizer = new MobileOptimizer()
export default {
async fetch(request, env, ctx) {
const userAgent = request.headers.get('User-Agent') || ''
const viewport = request.headers.get('Viewport')
const connectionType = request.headers.get('Downlink') || '4g'
// 检测设备类型
const deviceType = mobileOptimizer.detectDevice(userAgent, viewport)
const deviceProfile = mobileOptimizer.deviceProfiles[deviceType]
// 获取原始响应
let response = await fetch(request)
// 如果是 HTML 内容,进行优化
if (response.headers.get('Content-Type')?.includes('text/html')) {
const html = await response.text()
const optimizedHTML = mobileOptimizer.optimizeHTML(html, deviceProfile)
response = new Response(optimizedHTML, {
status: response.status,
statusText: response.statusText,
headers: response.headers
})
}
// 应用网络优化
response = mobileOptimizer.applyNetworkOptimizations(response, connectionType)
// 添加设备信息头
response.headers.set('X-Device-Type', deviceType)
response.headers.set('X-Edge-Optimized', 'true')
return response
}
}
🔍 性能监控与分析
边缘性能监控
javascript
// 边缘性能监控系统
class EdgePerformanceMonitor {
constructor(options = {}) {
this.region = options.region || 'unknown'
this.sampleRate = options.sampleRate || 0.1
this.metricsBuffer = []
this.maxBufferSize = options.maxBufferSize || 100
}
// 记录请求指标
recordRequestMetrics(request, response, startTime) {
const endTime = Date.now()
const duration = endTime - startTime
// 采样控制
if (Math.random() > this.sampleRate) return
const metrics = {
timestamp: startTime,
duration,
region: this.region,
method: request.method,
url: request.url,
status: response.status,
responseSize: response.headers.get('Content-Length') || 0,
cacheStatus: response.headers.get('CF-Cache-Status') || 'unknown',
country: request.cf?.country || 'unknown',
userAgent: this.parseUserAgent(request.headers.get('User-Agent')),
connectionType: request.headers.get('Downlink') || 'unknown'
}
this.metricsBuffer.push(metrics)
// 缓冲区满时发送数据
if (this.metricsBuffer.length >= this.maxBufferSize) {
this.flushMetrics()
}
}
// 解析用户代理
parseUserAgent(userAgent) {
if (!userAgent) return { browser: 'unknown', device: 'unknown' }
const browser = this.detectBrowser(userAgent)
const device = this.detectDevice(userAgent)
return { browser, device }
}
detectBrowser(userAgent) {
if (userAgent.includes('Chrome')) return 'Chrome'
if (userAgent.includes('Firefox')) return 'Firefox'
if (userAgent.includes('Safari')) return 'Safari'
if (userAgent.includes('Edge')) return 'Edge'
return 'Other'
}
detectDevice(userAgent) {
if (userAgent.includes('Mobile')) return 'Mobile'
if (userAgent.includes('Tablet')) return 'Tablet'
return 'Desktop'
}
// 发送指标数据
async flushMetrics() {
if (this.metricsBuffer.length === 0) return
const metrics = [...this.metricsBuffer]
this.metricsBuffer = []
try {
await fetch('https://analytics.example.com/edge-metrics', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Region': this.region
},
body: JSON.stringify({
metrics,
region: this.region,
timestamp: Date.now()
})
})
} catch (error) {
console.error('Failed to send metrics:', error)
// 重新添加到缓冲区
this.metricsBuffer.unshift(...metrics)
}
}
// 记录自定义事件
recordCustomEvent(eventName, data = {}) {
const event = {
type: 'custom',
name: eventName,
data,
timestamp: Date.now(),
region: this.region
}
this.metricsBuffer.push(event)
}
// 记录错误
recordError(error, context = {}) {
const errorEvent = {
type: 'error',
message: error.message,
stack: error.stack,
context,
timestamp: Date.now(),
region: this.region
}
this.metricsBuffer.push(errorEvent)
// 错误立即发送
this.flushMetrics()
}
}
// 实时性能分析
class RealTimeAnalyzer {
constructor() {
this.windowSize = 60000 // 1分钟窗口
this.metrics = []
this.alerts = []
}
// 添加指标
addMetric(metric) {
this.metrics.push(metric)
// 清理过期数据
const cutoff = Date.now() - this.windowSize
this.metrics = this.metrics.filter(m => m.timestamp > cutoff)
// 实时分析
this.analyzeMetrics()
}
// 分析指标
analyzeMetrics() {
if (this.metrics.length < 10) return
const recentMetrics = this.metrics.slice(-50)
// 计算平均响应时间
const avgResponseTime = recentMetrics.reduce((sum, m) => sum + m.duration, 0) / recentMetrics.length
// 计算错误率
const errorCount = recentMetrics.filter(m => m.status >= 400).length
const errorRate = errorCount / recentMetrics.length
// 检查异常
this.checkAnomalies(avgResponseTime, errorRate)
}
// 检查异常
checkAnomalies(avgResponseTime, errorRate) {
const alerts = []
// 响应时间异常
if (avgResponseTime > 1000) {
alerts.push({
type: 'high_latency',
message: `平均响应时间过高: ${avgResponseTime.toFixed(2)}ms`,
severity: avgResponseTime > 2000 ? 'critical' : 'warning',
timestamp: Date.now()
})
}
// 错误率异常
if (errorRate > 0.05) {
alerts.push({
type: 'high_error_rate',
message: `错误率过高: ${(errorRate * 100).toFixed(2)}%`,
severity: errorRate > 0.1 ? 'critical' : 'warning',
timestamp: Date.now()
})
}
// 发送告警
alerts.forEach(alert => this.sendAlert(alert))
}
// 发送告警
async sendAlert(alert) {
try {
await fetch('https://alerts.example.com/webhook', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(alert)
})
} catch (error) {
console.error('Failed to send alert:', error)
}
}
}
// 集成监控
const performanceMonitor = new EdgePerformanceMonitor({
region: 'asia-east',
sampleRate: 0.2
})
const realTimeAnalyzer = new RealTimeAnalyzer()
export default {
async fetch(request, env, ctx) {
const startTime = Date.now()
try {
// 处理请求
const response = await handleRequest(request)
// 记录性能指标
performanceMonitor.recordRequestMetrics(request, response, startTime)
realTimeAnalyzer.addMetric({
timestamp: startTime,
duration: Date.now() - startTime,
status: response.status
})
return response
} catch (error) {
// 记录错误
performanceMonitor.recordError(error, {
url: request.url,
method: request.method,
userAgent: request.headers.get('User-Agent')
})
throw error
}
}
}
🌍 全球化部署策略
智能路由
javascript
// 智能路由系统
class IntelligentRouter {
constructor() {
this.regionCapacity = new Map()
this.regionLatency = new Map()
this.loadBalancingStrategy = 'weighted-round-robin'
}
// 选择最佳区域
selectOptimalRegion(userLocation, availableRegions) {
const candidates = availableRegions.map(region => ({
region,
score: this.calculateRegionScore(region, userLocation)
}))
// 按分数排序
candidates.sort((a, b) => b.score - a.score)
return candidates[0].region
}
// 计算区域分数
calculateRegionScore(region, userLocation) {
let score = 100
// 地理距离因子
const distance = this.calculateDistance(region.location, userLocation)
score -= distance * 0.1
// 延迟因子
const latency = this.regionLatency.get(region.id) || 100
score -= latency * 0.5
// 容量因子
const capacity = this.regionCapacity.get(region.id) || 0.5
score *= capacity
// 网络质量因子
const networkQuality = this.getNetworkQuality(region.id, userLocation.country)
score *= networkQuality
return Math.max(0, score)
}
// 计算地理距离
calculateDistance(region1, region2) {
const R = 6371 // 地球半径(公里)
const dLat = this.toRad(region2.lat - region1.lat)
const dLon = this.toRad(region2.lon - region1.lon)
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(this.toRad(region1.lat)) * Math.cos(this.toRad(region2.lat)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2)
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
return R * c
}
toRad(degrees) {
return degrees * (Math.PI / 180)
}
// 获取网络质量
getNetworkQuality(regionId, country) {
// 基于历史数据的网络质量评估
const qualityMap = {
'us-east': { 'US': 0.95, 'CA': 0.90, 'default': 0.70 },
'eu-west': { 'GB': 0.95, 'DE': 0.93, 'FR': 0.91, 'default': 0.75 },
'asia-east': { 'CN': 0.85, 'JP': 0.95, 'KR': 0.93, 'default': 0.70 }
}
const regionQuality = qualityMap[regionId] || { 'default': 0.70 }
return regionQuality[country] || regionQuality['default']
}
// 动态负载均衡
async routeRequest(request, availableRegions) {
const userLocation = this.getUserLocation(request)
const optimalRegion = this.selectOptimalRegion(userLocation, availableRegions)
// 检查区域健康状态
const isHealthy = await this.checkRegionHealth(optimalRegion)
if (!isHealthy) {
// 选择备用区域
const backupRegions = availableRegions.filter(r => r.id !== optimalRegion.id)
const backupRegion = this.selectOptimalRegion(userLocation, backupRegions)
return this.forwardRequest(request, backupRegion)
}
return this.forwardRequest(request, optimalRegion)
}
// 转发请求
async forwardRequest(request, targetRegion) {
const targetUrl = new URL(request.url)
targetUrl.hostname = targetRegion.endpoint
const forwardedRequest = new Request(targetUrl, {
method: request.method,
headers: request.headers,
body: request.body
})
// 添加路由信息
forwardedRequest.headers.set('X-Routed-From', 'edge-router')
forwardedRequest.headers.set('X-Target-Region', targetRegion.id)
return await fetch(forwardedRequest)
}
// 检查区域健康状态
async checkRegionHealth(region) {
try {
const healthCheck = await fetch(`${region.endpoint}/health`, {
method: 'GET',
timeout: 5000
})
return healthCheck.ok
} catch (error) {
return false
}
}
// 获取用户位置
getUserLocation(request) {
return {
country: request.cf?.country || 'US',
region: request.cf?.region || 'unknown',
city: request.cf?.city || 'unknown',
lat: parseFloat(request.cf?.latitude) || 0,
lon: parseFloat(request.cf?.longitude) || 0
}
}
}
// 使用示例
const router = new IntelligentRouter()
const availableRegions = [
{
id: 'us-east',
endpoint: 'us-east.api.example.com',
location: { lat: 39.0458, lon: -76.6413 }
},
{
id: 'eu-west',
endpoint: 'eu-west.api.example.com',
location: { lat: 51.5074, lon: -0.1278 }
},
{
id: 'asia-east',
endpoint: 'asia-east.api.example.com',
location: { lat: 35.6762, lon: 139.6503 }
}
]
export default {
async fetch(request, env, ctx) {
// 智能路由
const response = await router.routeRequest(request, availableRegions)
// 添加路由信息到响应头
response.headers.set('X-Served-By', 'edge-router')
response.headers.set('X-Route-Time', Date.now())
return response
}
}
🔒 边缘安全
安全防护
javascript
// 边缘安全防护系统
class EdgeSecurityGuard {
constructor(options = {}) {
this.rateLimits = new Map()
this.blockedIPs = new Set()
this.suspiciousPatterns = [
/\b(union|select|insert|delete|drop|create|alter)\b/i,
/<script[^>]*>.*?<\/script>/i,
/javascript:/i,
/on\w+\s*=/i
]
this.maxRequestsPerMinute = options.maxRequestsPerMinute || 60
this.blockDuration = options.blockDuration || 300000 // 5分钟
}
// 检查请求安全性
async checkRequestSecurity(request) {
const clientIP = request.headers.get('CF-Connecting-IP') || 'unknown'
const userAgent = request.headers.get('User-Agent') || ''
const url = new URL(request.url)
// 检查 IP 黑名单
if (this.blockedIPs.has(clientIP)) {
return this.createSecurityResponse('IP_BLOCKED', 'IP address is blocked')
}
// 检查速率限制
const rateLimitResult = this.checkRateLimit(clientIP)
if (!rateLimitResult.allowed) {
return this.createSecurityResponse('RATE_LIMITED', 'Too many requests')
}
// 检查恶意模式
const maliciousCheck = this.checkMaliciousPatterns(request, url)
if (maliciousCheck.isMalicious) {
this.blockIP(clientIP)
return this.createSecurityResponse('MALICIOUS_REQUEST', maliciousCheck.reason)
}
// 检查 User-Agent
if (this.isSuspiciousUserAgent(userAgent)) {
return this.createSecurityResponse('SUSPICIOUS_USER_AGENT', 'Suspicious user agent')
}
// 检查地理位置
const geoCheck = this.checkGeographicRestrictions(request)
if (!geoCheck.allowed) {
return this.createSecurityResponse('GEO_BLOCKED', geoCheck.reason)
}
return { allowed: true }
}
// 速率限制检查
checkRateLimit(clientIP) {
const now = Date.now()
const windowStart = now - 60000 // 1分钟窗口
if (!this.rateLimits.has(clientIP)) {
this.rateLimits.set(clientIP, [])
}
const requests = this.rateLimits.get(clientIP)
// 清理过期请求
const validRequests = requests.filter(timestamp => timestamp > windowStart)
this.rateLimits.set(clientIP, validRequests)
// 检查是否超过限制
if (validRequests.length >= this.maxRequestsPerMinute) {
return { allowed: false, remaining: 0 }
}
// 记录当前请求
validRequests.push(now)
return {
allowed: true,
remaining: this.maxRequestsPerMinute - validRequests.length
}
}
// 检查恶意模式
checkMaliciousPatterns(request, url) {
// 检查 URL 参数
for (const [key, value] of url.searchParams) {
for (const pattern of this.suspiciousPatterns) {
if (pattern.test(value)) {
return {
isMalicious: true,
reason: `Suspicious pattern in parameter: ${key}`
}
}
}
}
// 检查路径
for (const pattern of this.suspiciousPatterns) {
if (pattern.test(url.pathname)) {
return {
isMalicious: true,
reason: 'Suspicious pattern in URL path'
}
}
}
// 检查请求头
const referer = request.headers.get('Referer') || ''
if (referer && this.suspiciousPatterns.some(pattern => pattern.test(referer))) {
return {
isMalicious: true,
reason: 'Suspicious pattern in referer'
}
}
return { isMalicious: false }
}
// 检查可疑 User-Agent
isSuspiciousUserAgent(userAgent) {
const suspiciousAgents = [
/bot/i,
/crawler/i,
/spider/i,
/scraper/i,
/curl/i,
/wget/i,
/python/i
]
// 允许合法的搜索引擎爬虫
const legitimateBots = [
/googlebot/i,
/bingbot/i,
/slurp/i,
/duckduckbot/i,
/baiduspider/i
]
const isSuspicious = suspiciousAgents.some(pattern => pattern.test(userAgent))
const isLegitimate = legitimateBots.some(pattern => pattern.test(userAgent))
return isSuspicious && !isLegitimate
}
// 地理位置限制检查
checkGeographicRestrictions(request) {
const country = request.cf?.country || 'unknown'
// 示例:阻止某些国家的访问
const blockedCountries = ['XX', 'YY'] // 替换为实际需要阻止的国家代码
if (blockedCountries.includes(country)) {
return {
allowed: false,
reason: `Access from ${country} is not allowed`
}
}
return { allowed: true }
}
// 阻止 IP
blockIP(ip) {
this.blockedIPs.add(ip)
// 设置自动解除阻止
setTimeout(() => {
this.blockedIPs.delete(ip)
}, this.blockDuration)
}
// 创建安全响应
createSecurityResponse(type, message) {
return {
allowed: false,
response: new Response(JSON.stringify({
error: type,
message: message,
timestamp: new Date().toISOString()
}), {
status: 403,
headers: {
'Content-Type': 'application/json',
'X-Security-Block': type
}
})
}
}
}
// 使用示例
const securityGuard = new EdgeSecurityGuard({
maxRequestsPerMinute: 100,
blockDuration: 600000 // 10分钟
})
export default {
async fetch(request, env, ctx) {
// 安全检查
const securityResult = await securityGuard.checkRequestSecurity(request)
if (!securityResult.allowed) {
return securityResult.response
}
// 继续处理正常请求
return await handleRequest(request)
}
}
边缘计算正在重新定义前端应用的架构模式,通过将计算能力推向网络边缘,我们可以为用户提供更快、更可靠的服务体验。合理利用边缘计算技术,结合智能缓存、性能监控和安全防护,可以构建出真正全球化的高性能前端应用。
拥抱边缘计算,构建无边界的前端应用!