引言
本文从技术和产品角度深入介绍我们开发的 OpenAPI 系统,这是一个基于Koa.js构建的高性能API计费解决方案,它不仅支持多种计费模式,还提供了强大的缓存机制、安全防护和灵活的请求处理能力。
系统架构
OpenAPI 系统采用了现代化的技术栈和架构设计:
- 后端框架:基于Koa.js构建,利用其异步特性实现高并发处理
- 数据存储:MongoDB用于持久化存储,Redis用于缓存和速率限制
- 前端界面:Vue.js构建的管理界面,包含Monaco编辑器支持 请求模板 编辑
系统的核心组件包括:
- API代理中间件
- 计费服务
- 速率限制器
- 缓存系统
- 安全认证模块
产品核心优势
1. 高性能设计
OpenAPI 系统在性能优化方面做了大量工作:
1.1 高效的HTTP连接管理
// 创建 keepAlive Agent
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 1000, // 连接保持时间
maxSockets: 100, // 并发连接数
maxFreeSockets: 10, // 允许的空闲连接数
timeout: TIMEOUT, // 超时时间
rejectUnauthorized: false // 忽略 SSL 证书错误
});
通过配置HTTP和HTTPS的Agent,系统实现了连接复用,大幅减少了TCP连接建立的开销。这在高并发场景下能显著提升性能,减少服务器资源消耗。
1.2 智能的重试机制
// 带重试的请求函数
async function retryableRequest(config, retries = RETRY_COUNT) {
try {
return await axiosInstance(config);
} catch (error) {
if (retries > 0 && (
error.code === 'ETIMEDOUT' ||
error.code === 'ECONNRESET' ||
error.code === 'ECONNREFUSED' ||
(error.response && error.response.status >= 500)
)) {
console.warn(`Retry attempt ${RETRY_COUNT - retries + 1} for ${config.url}`);
await delay(RETRY_DELAY * (RETRY_COUNT - retries));
return retryableRequest(config, retries - 1);
}
throw error;
}
}
系统实现了智能重试机制,可以自动处理临时性网络故障和上游服务暂时不可用的情况。重试策略采用了指数退避算法,避免了重试风暴,提高了系统的可靠性。
1.3 异步处理计费记录
系统将API调用和计费处理分离,API调用完成后异步处理计费记录,避免了计费处理对API响应时间的影响。
2. 高效缓存实现
缓存系统是 OpenAPI 的一大亮点,它极大地提升了系统性能和用户体验:
2.1 内存缓存实现
class MemoryCache {
constructor() {
this.cache = new Map();
this.timeouts = new Map();
}
set(key, value, ttlSeconds) {
this.cache.set(key, value);
if (ttlSeconds) {
// 清除旧的超时
if (this.timeouts.has(key)) {
clearTimeout(this.timeouts.get(key));
}
// 设置新的超时
const timeout = setTimeout(() => {
this.cache.delete(key);
this.timeouts.delete(key);
}, ttlSeconds * 1000);
this.timeouts.set(key, timeout);
}
}
// ...其他方法
}
系统实现了高效的内存缓存,使用Map数据结构存储缓存数据,并通过定时器实现缓存过期机制。这种设计比传统的数组遍历检查过期项更高效。
2.2 智能缓存策略
// 判断请求是否可缓存
function isCacheable(method, headers) {
// 只缓存GET请求,并且请求头没有指定no-cache
return method === 'GET' &&
(!headers['cache-control'] || !headers['cache-control'].includes('no-cache'));
}
// 获取缓存TTL(秒)
function getCacheTTL(resource) {
return resource.cacheTTL || 300; // 通过cacheTTL来自定义缓存时间, 默认5分钟
}
系统根据HTTP方法和请求头智能判断请求是否可缓存,并支持通过API资源配置自定义缓存时间。这种灵活的缓存策略能够适应不同API的缓存需求。
2.3 缓存键生成
// 生成缓存键
function generateCacheKey(ctx, url) {
const data = `${ctx.method}:${url}:${JSON.stringify(ctx.request.body)}:${JSON.stringify(ctx.request.querystring)}`;
return crypto.createHash('md5').update(data).digest('hex');
}
缓存键的生成考虑了HTTP方法、URL、请求体和查询参数,确保了缓存的精确匹配。使用MD5哈希算法生成固定长度的缓存键,提高了缓存系统的效率。
3. 安全性设计
OpenAPI 系统在安全性方面做了全面考量:
3.1 API密钥认证
系统实现了基于API密钥的认证机制,每个用户都有唯一的API密钥,用于身份验证和访问控制。
3.2 速率限制
exports.rateLimiter = async (ctx, next) => {
const endpoint = ctx.path.replace('/api/', '');
const apiKey = ctx.state.apiKey;
if (!apiKey) {
ctx.status = 401;
ctx.body = { error: 'API key required' };
return;
}
const maxRequests = objLimit[endpoint] || DEFAULT_MAX_REQUESTS;
const key = `ratelimit:${endpoint}/${apiKey}`;
try {
const isAllowed = await cache.rateLimit(key, maxRequests, RATE_LIMIT_WINDOW);
const currentCount = cache.get(key) || 0;
ctx.set('X-RateLimit-Limit', maxRequests);
ctx.set('X-RateLimit-Remaining', Math.max(0, maxRequests - currentCount));
if (!isAllowed) {
ctx.status = 429;
ctx.body = { error: `访问频率超限(${maxRequests}req/m)...` };
return;
}
return next();
} catch (error) {
logger.error('Rate limiter error:', error);
return next(); // Proceed even if rate limiting fails
}
};
系统实现了基于内存缓存的速率限制器,可以针对不同的API端点设置不同的速率限制,有效防止了API滥用和DoS攻击。速率限制器还会自动从数据库加载配置并定期更新,确保限制策略的及时生效。
3.3 输入验证和错误处理
系统对所有输入进行严格验证,防止注入攻击和其他安全威胁。同时,系统实现了全面的错误处理机制,确保在出现异常情况时能够优雅地处理并返回适当的错误信息。
4. 灵活的请求处理
4.1 函数式请求模板
系统最近升级了请求模板功能,支持使用JavaScript函数定义请求转换逻辑:
// 检查是否是函数字符串(以 function 开头)
if (typeof resource.requestTemplate === 'string' && resource.requestTemplate.trim().startsWith('function')) {
try {
// 将函数字符串转换为可执行函数
// 支持匿名函数和命名函数
const templateCode = resource.requestTemplate.trim();
let templateFunction = new Function('request', `
try {
return (${templateCode})(request);
} catch (err) {
console.error('Template function execution error:', err);
return {};
}
`);
// 执行函数并获取结果
const result = templateFunction(ctx.request);
if (result && typeof result === 'object') {
if (result.headers) {
headers = result.headers;
}
if (result.body) {
body = result.body
// 如果是FormData请求但模板返回了body,我们将转换为JSON请求
if (isMultipart) {
headers['content-type'] = 'application/json';
}
}
}
} catch (error) {
logger.error(`Error executing request template function: ${error.message}`);
}
}
这种函数式模板比传统的JSON模板更加灵活,可以实现复杂的请求转换逻辑,如条件判断、数据转换等。前端还配置了Monaco编辑器,提供JavaScript语法高亮,提升了模板编辑体验。
4.2 流式响应支持
系统支持流式响应,特别适用于处理大模型响应或需要实时数据的场景:
async function handleStreamProxy(ctx, apiResource, upstream, opt) {
const stream = new PassThrough();
ctx.body = stream;
// 设置 SSE headers
ctx.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
try {
// 处理特殊请求头
const headers = {
...opt.headers,
'api-key': opt.headers['api-key'] || '',
'Content-Type': 'application/json',
'Accept': 'text/event-stream'
};
// 移除不需要的头
delete headers.host;
delete headers['x-api-key'];
delete headers['content-length'];
const optA = {
method: ctx.method,
url: upstream,
data: {
...opt.body,
stream: true
},
headers,
responseType: 'stream'
};
// 转发请求到上游服务
const response = await axiosInstance(optA);
// 直接转发响应
response.data.pipe(stream);
} catch (error) {
console.error('Stream proxy error:', error);
stream.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
stream.end();
}
}
流式响应处理使系统能够支持现代AI API的流式输出,如OpenAI的流式聊天完成API。
5. 精确的Token计费
系统最近升级了token计费功能,支持更精确的计费方式:
- 输入输出分离计费:系统可以分别计算输入和输出token的费用,并设置不同的价格
- 智能识别输入token:对于常见的LLM API格式(如包含prompt或messages字段的请求),系统能够智能识别并计算输入token
- 灵活的计费模式:系统支持根据API资源的billingMode属性决定使用哪种计费模式
这种精确的token计费方式特别适合AI API提供商,可以更公平地反映API使用成本。
产品设计考量
1. 用户体验至上
OpenAPI 系统的设计始终以用户体验为中心:
- 简洁的API设计:遵循RESTful原则,API接口简洁明了,支持浏览器调用调试
- 详细的使用统计:提供实时使用量统计,帮助用户了解API使用情况
- 灵活的计费策略:支持多种计费模式,满足不同用户的需求
2. 可扩展性设计
系统在设计时充分考虑了可扩展性:
- 模块化架构:系统分为多个独立模块,如认证、代理、计费等,便于扩展和维护
- 插件化设计:关键功能如缓存、速率限制等都设计为可插拔的组件
- 配置驱动:大部分功能通过配置驱动,无需修改代码即可调整系统行为
3. 运维友好
系统设计了完善的日志和监控机制,便于运维人员排查问题和优化系统性能。同时,系统支持通过环境变量配置关键参数,便于在不同环境中部署。
技术实现对比
缓存实现对比
| 实现方式 | 优点 | 缺点 |
|---|---|---|
| 内存缓存 (当前实现) | 速度快,实现简单 | 不支持分布式,重启后缓存丢失 |
| Redis缓存 | 支持分布式,持久化 | 需要额外维护Redis服务 |
| 文件缓存 | 简单,持久化 | I/O开销大,性能较低 |
我们选择内存缓存作为主要实现,同时为分布式部署场景预留了Redis缓存的接口。
速率限制实现对比
| 实现方式 | 优点 | 缺点 |
|---|---|---|
| 内存计数器 (当前实现) | 速度快,实现简单 | 不支持分布式 |
| 滑动窗口 | 更精确的限流 | 实现复杂,资源消耗较大 |
| 令牌桶 | 允许突发流量 | 实现复杂 |
我们选择内存计数器作为速率限制的实现,在单机部署场景下提供了良好的性能和足够的准确性。
未来发展方向
- 支持多种货币:计划添加多币种支持,满足国际用户需求
- 计费预警功能:当用户接近月度限额时发送通知
- 自定义计费规则:允许用户定义更复杂的计费规则
- 计费报表导出:支持导出详细的计费报表
- 集成支付网关:直接在系统中完成充值和支付
结论
OpenAPI 系统通过高性能设计、高效缓存实现、全面的安全考量和灵活的请求处理能力,独立开发者提供了一个强大的计费解决方案。系统不仅满足了基本的计费需求,还通过精确的token计费、函数式请求模板等创新功能,提升了用户体验和系统灵活性。
作为独立开发者,更应追求技术卓越和产品完美, OpenAPI 系统正是这种追求的体现。我们相信,随着系统的不断发展和完善,它将为更多的API提供者创造价值。
本文由 OpenAPI 系统开发团队撰写,旨在分享我们在API计费领域的技术实践和产品思考。
正如一位用户所说:
" OpenAPI 让我第一次感受到,作为一个独立开发者,我也可以像大公司一样专业地提供API服务,并从中获得应有的回报。"
这或许正是 OpenAPI 最大的价值 —— 它让技术创造的价值得到了公正的评估和回报,让靠"爱发电"的开发者们看到了一条可持续发展的道路。
基础框架已开源,欢迎star和fork~ 评论区留言获取项目地址。