mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
feat: 添加API Key时间窗口限流功能并移除累计总量限制
- 新增时间窗口限流功能,支持按分钟设置时间窗口 - 支持在时间窗口内限制请求次数和Token使用量 - 移除原有的累计总量限制,只保留时间窗口限制 - Token统计包含所有4种类型:输入、输出、缓存创建、缓存读取 - 前端UI优化,明确显示限流参数的作用范围 - 限流触发时提供友好的错误提示和重置时间 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,8 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
expiresAt,
|
||||
claudeAccountId,
|
||||
concurrencyLimit,
|
||||
rateLimitWindow,
|
||||
rateLimitRequests,
|
||||
enableModelRestriction,
|
||||
restrictedModels
|
||||
} = req.body;
|
||||
@@ -58,6 +60,14 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
if (concurrencyLimit !== undefined && concurrencyLimit !== null && concurrencyLimit !== '' && (!Number.isInteger(Number(concurrencyLimit)) || Number(concurrencyLimit) < 0)) {
|
||||
return res.status(400).json({ error: 'Concurrency limit must be a non-negative integer' });
|
||||
}
|
||||
|
||||
if (rateLimitWindow !== undefined && rateLimitWindow !== null && rateLimitWindow !== '' && (!Number.isInteger(Number(rateLimitWindow)) || Number(rateLimitWindow) < 1)) {
|
||||
return res.status(400).json({ error: 'Rate limit window must be a positive integer (minutes)' });
|
||||
}
|
||||
|
||||
if (rateLimitRequests !== undefined && rateLimitRequests !== null && rateLimitRequests !== '' && (!Number.isInteger(Number(rateLimitRequests)) || Number(rateLimitRequests) < 1)) {
|
||||
return res.status(400).json({ error: 'Rate limit requests must be a positive integer' });
|
||||
}
|
||||
|
||||
// 验证模型限制字段
|
||||
if (enableModelRestriction !== undefined && typeof enableModelRestriction !== 'boolean') {
|
||||
@@ -75,6 +85,8 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
expiresAt,
|
||||
claudeAccountId,
|
||||
concurrencyLimit,
|
||||
rateLimitWindow,
|
||||
rateLimitRequests,
|
||||
enableModelRestriction,
|
||||
restrictedModels
|
||||
});
|
||||
@@ -91,7 +103,7 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
||||
try {
|
||||
const { keyId } = req.params;
|
||||
const { tokenLimit, concurrencyLimit, claudeAccountId, enableModelRestriction, restrictedModels } = req.body;
|
||||
const { tokenLimit, concurrencyLimit, rateLimitWindow, rateLimitRequests, claudeAccountId, enableModelRestriction, restrictedModels } = req.body;
|
||||
|
||||
// 只允许更新指定字段
|
||||
const updates = {};
|
||||
@@ -109,6 +121,20 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
|
||||
}
|
||||
updates.concurrencyLimit = Number(concurrencyLimit);
|
||||
}
|
||||
|
||||
if (rateLimitWindow !== undefined && rateLimitWindow !== null && rateLimitWindow !== '') {
|
||||
if (!Number.isInteger(Number(rateLimitWindow)) || Number(rateLimitWindow) < 0) {
|
||||
return res.status(400).json({ error: 'Rate limit window must be a non-negative integer (minutes)' });
|
||||
}
|
||||
updates.rateLimitWindow = Number(rateLimitWindow);
|
||||
}
|
||||
|
||||
if (rateLimitRequests !== undefined && rateLimitRequests !== null && rateLimitRequests !== '') {
|
||||
if (!Number.isInteger(Number(rateLimitRequests)) || Number(rateLimitRequests) < 0) {
|
||||
return res.status(400).json({ error: 'Rate limit requests must be a non-negative integer' });
|
||||
}
|
||||
updates.rateLimitRequests = Number(rateLimitRequests);
|
||||
}
|
||||
|
||||
if (claudeAccountId !== undefined) {
|
||||
// 空字符串表示解绑,null或空字符串都设置为空字符串
|
||||
|
||||
Reference in New Issue
Block a user