mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
chore: 去除claude转发冗余代码
This commit is contained in:
@@ -1876,156 +1876,6 @@ class ClaudeRelayService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🌊 发送流式请求到Claude API
|
|
||||||
async _makeClaudeStreamRequest(
|
|
||||||
body,
|
|
||||||
accessToken,
|
|
||||||
proxyAgent,
|
|
||||||
clientHeaders,
|
|
||||||
responseStream,
|
|
||||||
requestOptions = {}
|
|
||||||
) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const url = new URL(this.claudeApiUrl)
|
|
||||||
|
|
||||||
// 获取过滤后的客户端 headers
|
|
||||||
const filteredHeaders = this._filterClientHeaders(clientHeaders)
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
hostname: url.hostname,
|
|
||||||
port: url.port || 443,
|
|
||||||
path: url.pathname,
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${accessToken}`,
|
|
||||||
'anthropic-version': this.apiVersion,
|
|
||||||
...filteredHeaders
|
|
||||||
},
|
|
||||||
agent: proxyAgent,
|
|
||||||
timeout: config.requestTimeout || 600000
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果客户端没有提供 User-Agent,使用默认值
|
|
||||||
if (!filteredHeaders['User-Agent'] && !filteredHeaders['user-agent']) {
|
|
||||||
// 第三个方法不支持统一 User-Agent,使用简化逻辑
|
|
||||||
const userAgent =
|
|
||||||
clientHeaders?.['user-agent'] ||
|
|
||||||
clientHeaders?.['User-Agent'] ||
|
|
||||||
'claude-cli/1.0.102 (external, cli)'
|
|
||||||
options.headers['User-Agent'] = userAgent
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用自定义的 betaHeader 或默认值
|
|
||||||
const betaHeader =
|
|
||||||
requestOptions?.betaHeader !== undefined ? requestOptions.betaHeader : this.betaHeader
|
|
||||||
if (betaHeader) {
|
|
||||||
options.headers['anthropic-beta'] = betaHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
const req = https.request(options, (res) => {
|
|
||||||
// 设置响应头
|
|
||||||
responseStream.statusCode = res.statusCode
|
|
||||||
Object.keys(res.headers).forEach((key) => {
|
|
||||||
responseStream.setHeader(key, res.headers[key])
|
|
||||||
})
|
|
||||||
|
|
||||||
// 管道响应数据
|
|
||||||
res.pipe(responseStream)
|
|
||||||
|
|
||||||
res.on('end', () => {
|
|
||||||
logger.debug('🌊 Claude stream response completed')
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
req.on('error', async (error) => {
|
|
||||||
logger.error(`❌ Claude stream request error:`, error.message, {
|
|
||||||
code: error.code,
|
|
||||||
errno: error.errno,
|
|
||||||
syscall: error.syscall
|
|
||||||
})
|
|
||||||
|
|
||||||
// 根据错误类型提供更具体的错误信息
|
|
||||||
let errorMessage = 'Upstream request failed'
|
|
||||||
let statusCode = 500
|
|
||||||
if (error.code === 'ECONNRESET') {
|
|
||||||
errorMessage = 'Connection reset by Claude API server'
|
|
||||||
statusCode = 502
|
|
||||||
} else if (error.code === 'ENOTFOUND') {
|
|
||||||
errorMessage = 'Unable to resolve Claude API hostname'
|
|
||||||
statusCode = 502
|
|
||||||
} else if (error.code === 'ECONNREFUSED') {
|
|
||||||
errorMessage = 'Connection refused by Claude API server'
|
|
||||||
statusCode = 502
|
|
||||||
} else if (error.code === 'ETIMEDOUT') {
|
|
||||||
errorMessage = 'Connection timed out to Claude API server'
|
|
||||||
statusCode = 504
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!responseStream.headersSent) {
|
|
||||||
responseStream.writeHead(statusCode, {
|
|
||||||
'Content-Type': 'text/event-stream',
|
|
||||||
'Cache-Control': 'no-cache',
|
|
||||||
Connection: 'keep-alive'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!responseStream.destroyed) {
|
|
||||||
// 发送 SSE 错误事件
|
|
||||||
responseStream.write('event: error\n')
|
|
||||||
responseStream.write(
|
|
||||||
`data: ${JSON.stringify({
|
|
||||||
error: errorMessage,
|
|
||||||
code: error.code,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
})}\n\n`
|
|
||||||
)
|
|
||||||
responseStream.end()
|
|
||||||
}
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
req.on('timeout', async () => {
|
|
||||||
req.destroy()
|
|
||||||
logger.error(`❌ Claude stream request timeout`)
|
|
||||||
|
|
||||||
if (!responseStream.headersSent) {
|
|
||||||
responseStream.writeHead(504, {
|
|
||||||
'Content-Type': 'text/event-stream',
|
|
||||||
'Cache-Control': 'no-cache',
|
|
||||||
Connection: 'keep-alive'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (!responseStream.destroyed) {
|
|
||||||
// 发送 SSE 错误事件
|
|
||||||
responseStream.write('event: error\n')
|
|
||||||
responseStream.write(
|
|
||||||
`data: ${JSON.stringify({
|
|
||||||
error: 'Request timeout',
|
|
||||||
code: 'TIMEOUT',
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
})}\n\n`
|
|
||||||
)
|
|
||||||
responseStream.end()
|
|
||||||
}
|
|
||||||
reject(new Error('Request timeout'))
|
|
||||||
})
|
|
||||||
|
|
||||||
// 处理客户端断开连接
|
|
||||||
responseStream.on('close', () => {
|
|
||||||
logger.debug('🔌 Client disconnected, cleaning up stream')
|
|
||||||
if (!req.destroyed) {
|
|
||||||
req.destroy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 写入请求体
|
|
||||||
req.write(JSON.stringify(body))
|
|
||||||
req.end()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🛠️ 统一的错误处理方法
|
// 🛠️ 统一的错误处理方法
|
||||||
async _handleServerError(accountId, statusCode, _sessionHash = null, context = '') {
|
async _handleServerError(accountId, statusCode, _sessionHash = null, context = '') {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user