构建动态 OG 图像系统:架构与实现 🏗️
大家好!👋 在我们的“让 OpenGraph 发挥作用”系列中探索了 OpenGraph 基础知识之后,让我们深入构建一个完整的、可用于生产的 OG 图像系统。我将分享我在为 gleam.so 构建该系统时学到的知识。
系统概述
首先,让我们看看我们正在构建什么:
interface OGSystem {
generator: {
render: (template: Template, data: InputData) => Promise;
optimize: (image: Buffer) => Promise;
};
cache: {
get: (key: string) => Promise;
set: (key: string, image: Buffer) => Promise;
};
storage: {
upload: (key: string, image: Buffer) => Promise;
getUrl: (key: string) => string;
};
} 关键要求:
技术实现
1. 核心生成服务
// services/og-generator.ts
import { ImageResponse } from '@vercel/og';
import sharp from 'sharp';
export class OGGenerator {
async render(template: Template, data: InputData): Promise {
try {
// 1. Prepare template
const element = await this.prepareTemplate(template, data);
// 2. Generate image
const imageResponse = new ImageResponse(element, {
width: template.width,
height: template.height,
// Performance optimizations
emoji: 'twemoji',
fonts: await this.loadFonts(),
});
// 3. Get buffer
return imageResponse.arrayBuffer();
} catch (error) {
console.error('OG Generation failed:', error);
return this.generateFallback(template, data);
}
}
async optimize(buffer: Buffer): Promise {
return sharp(buffer)
.jpeg({
quality: 85,
progressive: true,
force: false,
})
.png({
compressionLevel: 9,
palette: true,
})
.toBuffer();
}
} 2.缓存层
// services/og-cache.ts
import { Redis } from 'ioredis';
export class OGCache {
private redis: Redis;
private ttl: number = 7 * 24 * 60 * 60; // 1 week
async get(key: string): Promise {
try {
const cached = await this.redis.get(key);
return cached ? Buffer.from(cached, 'base64') : null;
} catch (error) {
console.error('Cache fetch failed:', error);
return null;
}
}
async set(key: string, image: Buffer): Promise {
try {
await this.redis.set(
key,
image.toString('base64'),
'EX',
this.ttl
);
} catch (error) {
console.error('Cache set failed:', error);
}
}
} 3. API 实现
// pages/api/og/[key].tsx
export const config = {
runtime: 'edge',
}
export default async function handler(req: Request) {
try {
// 1. Parse request
const { searchParams } = new URL(req.url);
const template = searchParams.get('template');
const data = JSON.parse(searchParams.get('data') || '{}');
// 2. Generate cache key
const cacheKey = generateCacheKey(template, data);
// 3. Check cache
const cached = await cache.get(cacheKey);
if (cached) {
return new Response(cached, {
headers: getImageHeaders(cached),
});
}
// 4. Generate new image
const generator = new OGGenerator();
const image = await generator.render(template, data);
const optimized = await generator.optimize(image);
// 5. Cache result
await cache.set(cacheKey, optimized);
return new Response(optimized, {
headers: getImageHeaders(optimized),
});
} catch (error) {
console.error('OG API failed:', error);
return new Response(await generateFallback(), {
status: 500,
});
}
}性能考虑
1.缓存策略
interface CacheStrategy {
layers: {
edge: EdgeCache; // Vercel Edge Cache
application: Redis; // Redis Cache
cdn: CloudflareKV; // CDN Cache
};
policies: {
ttl: number; // Cache duration
stale: boolean; // Serve stale content
revalidate: boolean; // Background refresh
};
}2.资源优化
// services/resource-optimizer.ts
export class ResourceOptimizer {
// Preload common fonts
private fontLoader = new FontLoader([
{ name: 'Inter', weight: 400, style: 'normal' },
{ name: 'Inter', weight: 700, style: 'normal' },
]);
// Optimize images
private imageOptimizer = new ImageOptimizer({
jpeg: { quality: 85 },
png: { compressionLevel: 9 },
webp: { quality: 85 },
});
// Memory management
private memoryManager = new MemoryManager({
maxSize: '1GB',
cleanupInterval: '5m',
});
}监控和调试
1. 性能监控
// monitoring/performance.ts
export class OGMonitor {
async trackGeneration(key: string, timing: Timing) {
await this.metrics.record({
name: 'og_generation',
value: timing.duration,
tags: {
template: key,
cache: timing.cached ? 'hit' : 'miss',
error: timing.error ? 'true' : 'false',
},
});
}
}2. 错误追踪
// monitoring/errors.ts
export class ErrorTracker {
async captureError(error: Error, context: Context) {
// 1. Log error
console.error('OG Error:', {
error,
context,
stack: error.stack,
});
// 2. Track in monitoring
await this.monitor.trackError({
type: 'og_generation_error',
error,
context,
});
// 3. Alert if critical
if (this.isCritical(error)) {
await this.alertTeam(error);
}
}
}未来的改进🚀
自己尝试一下!🎯
我在 gleam.so 中实现了所有这些原则。而对于黑色星期五,
🔥 当前优惠:所有付费计划 75% 折扣
抓住机会,抢占你最喜欢的设计 🎨
想要看看这个系统的实际运行情况吗?留下评论,告诉我你的用例,我会帮你实现它!