mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
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:
@@ -12,6 +12,9 @@ const { authenticateApiKey } = require('../middleware/auth');
|
||||
const claudeRelayService = require('../services/claudeRelayService');
|
||||
const openaiToClaude = require('../services/openaiToClaude');
|
||||
const apiKeyService = require('../services/apiKeyService');
|
||||
const claudeAccountService = require('../services/claudeAccountService');
|
||||
const claudeCodeHeadersService = require('../services/claudeCodeHeadersService');
|
||||
const sessionHelper = require('../utils/sessionHelper');
|
||||
|
||||
// 加载模型定价数据
|
||||
let modelPricingData = {};
|
||||
@@ -199,6 +202,19 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
||||
}
|
||||
}
|
||||
|
||||
// 生成会话哈希用于sticky会话
|
||||
const sessionHash = sessionHelper.generateSessionHash(claudeRequest);
|
||||
|
||||
// 选择可用的Claude账户
|
||||
const accountId = await claudeAccountService.selectAccountForApiKey(apiKeyData, sessionHash);
|
||||
|
||||
// 获取该账号存储的 Claude Code headers
|
||||
const claudeCodeHeaders = await claudeCodeHeadersService.getAccountHeaders(accountId);
|
||||
|
||||
logger.debug(`📋 Using Claude Code headers for account ${accountId}:`, {
|
||||
userAgent: claudeCodeHeaders['user-agent']
|
||||
});
|
||||
|
||||
// 处理流式请求
|
||||
if (claudeRequest.stream) {
|
||||
logger.info(`🌊 Processing OpenAI stream request for model: ${req.body.model}`);
|
||||
@@ -221,12 +237,12 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
||||
}
|
||||
});
|
||||
|
||||
// 使用转换后的响应流 (使用 OAuth-only beta header,不传递客户端 headers)
|
||||
// 使用转换后的响应流 (使用 OAuth-only beta header,添加 Claude Code 必需的 headers)
|
||||
await claudeRelayService.relayStreamRequestWithUsageCapture(
|
||||
claudeRequest,
|
||||
apiKeyData,
|
||||
res,
|
||||
{},
|
||||
claudeCodeHeaders,
|
||||
(usage) => {
|
||||
// 记录使用统计
|
||||
if (usage && usage.input_tokens !== undefined && usage.output_tokens !== undefined) {
|
||||
@@ -252,20 +268,20 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
||||
(chunk) => {
|
||||
return openaiToClaude.convertStreamChunk(chunk, req.body.model);
|
||||
},
|
||||
{ betaHeader: 'oauth-2025-04-20' }
|
||||
{ betaHeader: 'oauth-2025-04-20,claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14' }
|
||||
);
|
||||
|
||||
} else {
|
||||
// 非流式请求
|
||||
logger.info(`📄 Processing OpenAI non-stream request for model: ${req.body.model}`);
|
||||
|
||||
// 发送请求到 Claude (使用 OAuth-only beta header,不传递客户端 headers)
|
||||
// 发送请求到 Claude (使用 OAuth-only beta header,添加 Claude Code 必需的 headers)
|
||||
const claudeResponse = await claudeRelayService.relayRequest(
|
||||
claudeRequest,
|
||||
apiKeyData,
|
||||
req,
|
||||
res,
|
||||
{},
|
||||
claudeCodeHeaders,
|
||||
{ betaHeader: 'oauth-2025-04-20' }
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user