fix: 改进socket hang up和网络错误处理机制

- 修复socket hang up错误导致返回空字符串的问题
- 改进非流式请求的错误处理,根据错误类型返回适当的HTTP状态码
- 优化流式请求的错误处理,返回SSE格式的错误事件
- 增强错误日志记录,包含详细的网络错误信息
- 确保在任何情况下都返回有效的JSON响应格式

修复内容:
- ECONNRESET错误返回502状态码和明确的错误信息
- ENOTFOUND错误返回502状态码和DNS解析失败信息
- ECONNREFUSED错误返回502状态码和连接被拒绝信息
- ETIMEDOUT错误返回504状态码和超时信息
- 流式请求错误时返回符合SSE规范的错误事件

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-16 17:56:29 +08:00
parent 06ad6ec440
commit 8ca9ffee68
2 changed files with 155 additions and 18 deletions

View File

@@ -145,13 +145,41 @@ router.post('/v1/messages', authenticateApiKey, async (req, res) => {
logger.api(`✅ Request completed in ${duration}ms for key: ${req.apiKey.name}`);
} catch (error) {
logger.error('❌ Claude relay error:', error);
logger.error('❌ Claude relay error:', error.message, {
code: error.code,
stack: error.stack
});
// 确保在任何情况下都能返回有效的JSON响应
if (!res.headersSent) {
res.status(500).json({
error: 'Relay service error',
message: error.message
// 根据错误类型设置适当的状态码
let statusCode = 500;
let errorType = 'Relay service error';
if (error.message.includes('Connection reset') || error.message.includes('socket hang up')) {
statusCode = 502;
errorType = 'Upstream connection error';
} else if (error.message.includes('Connection refused')) {
statusCode = 502;
errorType = 'Upstream service unavailable';
} else if (error.message.includes('timeout')) {
statusCode = 504;
errorType = 'Upstream timeout';
} else if (error.message.includes('resolve') || error.message.includes('ENOTFOUND')) {
statusCode = 502;
errorType = 'Upstream hostname resolution failed';
}
res.status(statusCode).json({
error: errorType,
message: error.message || 'An unexpected error occurred',
timestamp: new Date().toISOString()
});
} else {
// 如果响应头已经发送,尝试结束响应
if (!res.destroyed && !res.finished) {
res.end();
}
}
}
});