feat: 实现 Claude Code headers 动态管理功能

- 创建 claudeCodeHeadersService 管理各账号的 Claude Code headers
- 自动捕获成功请求的 headers 并按账号存储在 Redis
- 智能版本管理,只保留最新版本的 headers
- OpenAI 转发时根据账号动态获取对应的 headers
- 添加管理端点查看和清除各账号的 headers 信息
- 完整支持 Claude Code 必需的 beta headers

解决了 "This credential is only authorized for use with Claude Code" 错误
避免了固定版本号带来的风控问题

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-22 16:03:31 +08:00
parent b2ad2a4a61
commit dabf3bf7ea
6 changed files with 410 additions and 12 deletions

View File

@@ -8,6 +8,7 @@ const logger = require('../utils/logger');
const oauthHelper = require('../utils/oauthHelper');
const CostCalculator = require('../utils/costCalculator');
const pricingService = require('../services/pricingService');
const claudeCodeHeadersService = require('../services/claudeCodeHeadersService');
const router = express.Router();
@@ -1558,4 +1559,52 @@ router.get('/usage-costs', authenticateAdmin, async (req, res) => {
}
});
// 📋 获取所有账号的 Claude Code headers 信息
router.get('/claude-code-headers', authenticateAdmin, async (req, res) => {
try {
const allHeaders = await claudeCodeHeadersService.getAllAccountHeaders();
// 获取所有 Claude 账号信息
const accounts = await claudeAccountService.getAllAccounts();
const accountMap = {};
accounts.forEach(account => {
accountMap[account.id] = account.name;
});
// 格式化输出
const formattedData = Object.entries(allHeaders).map(([accountId, data]) => ({
accountId,
accountName: accountMap[accountId] || 'Unknown',
version: data.version,
userAgent: data.headers['user-agent'],
updatedAt: data.updatedAt,
headers: data.headers
}));
res.json({
success: true,
data: formattedData
});
} catch (error) {
logger.error('❌ Failed to get Claude Code headers:', error);
res.status(500).json({ error: 'Failed to get Claude Code headers', message: error.message });
}
});
// 🗑️ 清除指定账号的 Claude Code headers
router.delete('/claude-code-headers/:accountId', authenticateAdmin, async (req, res) => {
try {
const { accountId } = req.params;
await claudeCodeHeadersService.clearAccountHeaders(accountId);
res.json({
success: true,
message: `Claude Code headers cleared for account ${accountId}`
});
} catch (error) {
logger.error('❌ Failed to clear Claude Code headers:', error);
res.status(500).json({ error: 'Failed to clear Claude Code headers', message: error.message });
}
});
module.exports = router;