mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
feat: 适配claude的400错误码
This commit is contained in:
@@ -38,6 +38,57 @@ class ClaudeRelayService {
|
|||||||
return `此专属账号的Opus模型已达到周使用限制,将于 ${formattedReset} 自动恢复,请尝试切换其他模型后再试。`
|
return `此专属账号的Opus模型已达到周使用限制,将于 ${formattedReset} 自动恢复,请尝试切换其他模型后再试。`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🧾 提取错误消息文本
|
||||||
|
_extractErrorMessage(body) {
|
||||||
|
if (!body) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof body === 'string') {
|
||||||
|
const trimmed = body.trim()
|
||||||
|
if (!trimmed) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(trimmed)
|
||||||
|
return this._extractErrorMessage(parsed)
|
||||||
|
} catch (error) {
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof body === 'object') {
|
||||||
|
if (typeof body.error === 'string') {
|
||||||
|
return body.error
|
||||||
|
}
|
||||||
|
if (body.error && typeof body.error === 'object') {
|
||||||
|
if (typeof body.error.message === 'string') {
|
||||||
|
return body.error.message
|
||||||
|
}
|
||||||
|
if (typeof body.error.error === 'string') {
|
||||||
|
return body.error.error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof body.message === 'string') {
|
||||||
|
return body.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🚫 检查是否为组织被禁用错误
|
||||||
|
_isOrganizationDisabledError(statusCode, body) {
|
||||||
|
if (statusCode !== 400) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const message = this._extractErrorMessage(body)
|
||||||
|
if (!message) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return message.toLowerCase().includes('this organization has been disabled')
|
||||||
|
}
|
||||||
|
|
||||||
// 🔍 判断是否是真实的 Claude Code 请求
|
// 🔍 判断是否是真实的 Claude Code 请求
|
||||||
isRealClaudeCodeRequest(requestBody) {
|
isRealClaudeCodeRequest(requestBody) {
|
||||||
return ClaudeCodeValidator.hasClaudeCodeSystemPrompt(requestBody)
|
return ClaudeCodeValidator.hasClaudeCodeSystemPrompt(requestBody)
|
||||||
@@ -189,6 +240,10 @@ class ClaudeRelayService {
|
|||||||
let isRateLimited = false
|
let isRateLimited = false
|
||||||
let rateLimitResetTimestamp = null
|
let rateLimitResetTimestamp = null
|
||||||
let dedicatedRateLimitMessage = null
|
let dedicatedRateLimitMessage = null
|
||||||
|
const organizationDisabledError = this._isOrganizationDisabledError(
|
||||||
|
response.statusCode,
|
||||||
|
response.body
|
||||||
|
)
|
||||||
|
|
||||||
// 检查是否为401状态码(未授权)
|
// 检查是否为401状态码(未授权)
|
||||||
if (response.statusCode === 401) {
|
if (response.statusCode === 401) {
|
||||||
@@ -221,6 +276,13 @@ class ClaudeRelayService {
|
|||||||
)
|
)
|
||||||
await unifiedClaudeScheduler.markAccountBlocked(accountId, accountType, sessionHash)
|
await unifiedClaudeScheduler.markAccountBlocked(accountId, accountType, sessionHash)
|
||||||
}
|
}
|
||||||
|
// 检查是否返回组织被禁用错误(400状态码)
|
||||||
|
else if (organizationDisabledError) {
|
||||||
|
logger.error(
|
||||||
|
`🚫 Organization disabled error (400) detected for account ${accountId}, marking as blocked`
|
||||||
|
)
|
||||||
|
await unifiedClaudeScheduler.markAccountBlocked(accountId, accountType, sessionHash)
|
||||||
|
}
|
||||||
// 检查是否为529状态码(服务过载)
|
// 检查是否为529状态码(服务过载)
|
||||||
else if (response.statusCode === 529) {
|
else if (response.statusCode === 529) {
|
||||||
logger.warn(`🚫 Overload error (529) detected for account ${accountId}`)
|
logger.warn(`🚫 Overload error (529) detected for account ${accountId}`)
|
||||||
@@ -1253,6 +1315,25 @@ class ClaudeRelayService {
|
|||||||
`❌ Claude API error response (Account: ${account?.name || accountId}):`,
|
`❌ Claude API error response (Account: ${account?.name || accountId}):`,
|
||||||
errorData
|
errorData
|
||||||
)
|
)
|
||||||
|
if (this._isOrganizationDisabledError(res.statusCode, errorData)) {
|
||||||
|
;(async () => {
|
||||||
|
try {
|
||||||
|
logger.error(
|
||||||
|
`🚫 [Stream] Organization disabled error (400) detected for account ${accountId}, marking as blocked`
|
||||||
|
)
|
||||||
|
await unifiedClaudeScheduler.markAccountBlocked(
|
||||||
|
accountId,
|
||||||
|
accountType,
|
||||||
|
sessionHash
|
||||||
|
)
|
||||||
|
} catch (markError) {
|
||||||
|
logger.error(
|
||||||
|
`❌ [Stream] Failed to mark account ${accountId} as blocked after organization disabled error:`,
|
||||||
|
markError
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
if (!responseStream.destroyed) {
|
if (!responseStream.destroyed) {
|
||||||
// 发送错误事件
|
// 发送错误事件
|
||||||
responseStream.write('event: error\n')
|
responseStream.write('event: error\n')
|
||||||
|
|||||||
Reference in New Issue
Block a user