fix: 修复因代理ip不可用导致axios的proxy回退到环境变量代理问题

This commit is contained in:
shaw
2025-10-18 11:00:43 +08:00
parent 6ea2012ab1
commit 1ed0ca31ec
14 changed files with 133 additions and 35 deletions

View File

@@ -7183,6 +7183,7 @@ router.post('/openai-accounts/exchange-code', authenticateAdmin, async (req, res
// 配置代理(如果有) // 配置代理(如果有)
const proxyAgent = ProxyHelper.createProxyAgent(sessionData.proxy) const proxyAgent = ProxyHelper.createProxyAgent(sessionData.proxy)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false axiosConfig.proxy = false
} }

View File

@@ -332,6 +332,7 @@ const handleResponses = async (req, res) => {
// 如果有代理,添加代理配置 // 如果有代理,添加代理配置
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false axiosConfig.proxy = false
logger.info(`🌐 Using proxy for OpenAI request: ${ProxyHelper.getProxyDescription(proxy)}`) logger.info(`🌐 Using proxy for OpenAI request: ${ProxyHelper.getProxyDescription(proxy)}`)

View File

@@ -82,7 +82,9 @@ async function handleAzureOpenAIRequest({
// 如果有代理,添加代理配置 // 如果有代理,添加代理配置
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
// 为代理添加额外的keep-alive设置 // 为代理添加额外的keep-alive设置
if (proxyAgent.options) { if (proxyAgent.options) {
proxyAgent.options.keepAlive = true proxyAgent.options.keepAlive = true

View File

@@ -121,12 +121,17 @@ class CcrRelayService {
'User-Agent': userAgent, 'User-Agent': userAgent,
...filteredHeaders ...filteredHeaders
}, },
httpsAgent: proxyAgent,
timeout: config.requestTimeout || 600000, timeout: config.requestTimeout || 600000,
signal: abortController.signal, signal: abortController.signal,
validateStatus: () => true // 接受所有状态码 validateStatus: () => true // 接受所有状态码
} }
if (proxyAgent) {
requestConfig.httpAgent = proxyAgent
requestConfig.httpsAgent = proxyAgent
requestConfig.proxy = false
}
// 根据 API Key 格式选择认证方式 // 根据 API Key 格式选择认证方式
if (account.apiKey && account.apiKey.startsWith('sk-ant-')) { if (account.apiKey && account.apiKey.startsWith('sk-ant-')) {
// Anthropic 官方 API Key 使用 x-api-key // Anthropic 官方 API Key 使用 x-api-key
@@ -345,12 +350,17 @@ class CcrRelayService {
'User-Agent': userAgent, 'User-Agent': userAgent,
...filteredHeaders ...filteredHeaders
}, },
httpsAgent: proxyAgent,
timeout: config.requestTimeout || 600000, timeout: config.requestTimeout || 600000,
responseType: 'stream', responseType: 'stream',
validateStatus: () => true // 接受所有状态码 validateStatus: () => true // 接受所有状态码
} }
if (proxyAgent) {
requestConfig.httpAgent = proxyAgent
requestConfig.httpsAgent = proxyAgent
requestConfig.proxy = false
}
// 根据 API Key 格式选择认证方式 // 根据 API Key 格式选择认证方式
if (account.apiKey && account.apiKey.startsWith('sk-ant-')) { if (account.apiKey && account.apiKey.startsWith('sk-ant-')) {
// Anthropic 官方 API Key 使用 x-api-key // Anthropic 官方 API Key 使用 x-api-key

View File

@@ -248,14 +248,7 @@ class ClaudeAccountService {
// 创建代理agent // 创建代理agent
const agent = this._createProxyAgent(accountData.proxy) const agent = this._createProxyAgent(accountData.proxy)
const response = await axios.post( const axiosConfig = {
this.claudeApiUrl,
{
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: this.claudeOauthClientId
},
{
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Accept: 'application/json, text/plain, */*', Accept: 'application/json, text/plain, */*',
@@ -264,9 +257,23 @@ class ClaudeAccountService {
Referer: 'https://claude.ai/', Referer: 'https://claude.ai/',
Origin: 'https://claude.ai' Origin: 'https://claude.ai'
}, },
httpsAgent: agent,
timeout: 30000 timeout: 30000
} }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.post(
this.claudeApiUrl,
{
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: this.claudeOauthClientId
},
axiosConfig
) )
if (response.status === 200) { if (response.status === 200) {
@@ -1824,7 +1831,7 @@ class ClaudeAccountService {
logger.debug(`📊 Fetching OAuth usage for account: ${accountData.name} (${accountId})`) logger.debug(`📊 Fetching OAuth usage for account: ${accountData.name} (${accountId})`)
// 请求 OAuth usage 接口 // 请求 OAuth usage 接口
const response = await axios.get('https://api.anthropic.com/api/oauth/usage', { const axiosConfig = {
headers: { headers: {
Authorization: `Bearer ${accessToken}`, Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -1833,9 +1840,16 @@ class ClaudeAccountService {
'User-Agent': 'claude-cli/1.0.56 (external, cli)', 'User-Agent': 'claude-cli/1.0.56 (external, cli)',
'Accept-Language': 'en-US,en;q=0.9' 'Accept-Language': 'en-US,en;q=0.9'
}, },
httpsAgent: agent,
timeout: 15000 timeout: 15000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.get('https://api.anthropic.com/api/oauth/usage', axiosConfig)
if (response.status === 200 && response.data) { if (response.status === 200 && response.data) {
logger.debug('✅ Successfully fetched OAuth usage data:', { logger.debug('✅ Successfully fetched OAuth usage data:', {
@@ -2003,7 +2017,7 @@ class ClaudeAccountService {
logger.info(`📊 Fetching profile info for account: ${accountData.name} (${accountId})`) logger.info(`📊 Fetching profile info for account: ${accountData.name} (${accountId})`)
// 请求 profile 接口 // 请求 profile 接口
const response = await axios.get('https://api.anthropic.com/api/oauth/profile', { const axiosConfig = {
headers: { headers: {
Authorization: `Bearer ${accessToken}`, Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -2011,9 +2025,16 @@ class ClaudeAccountService {
'User-Agent': 'claude-cli/1.0.56 (external, cli)', 'User-Agent': 'claude-cli/1.0.56 (external, cli)',
'Accept-Language': 'en-US,en;q=0.9' 'Accept-Language': 'en-US,en;q=0.9'
}, },
httpsAgent: agent,
timeout: 15000 timeout: 15000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.get('https://api.anthropic.com/api/oauth/profile', axiosConfig)
if (response.status === 200 && response.data) { if (response.status === 200 && response.data) {
const profileData = response.data const profileData = response.data

View File

@@ -127,12 +127,17 @@ class ClaudeConsoleRelayService {
'User-Agent': userAgent, 'User-Agent': userAgent,
...filteredHeaders ...filteredHeaders
}, },
httpsAgent: proxyAgent,
timeout: config.requestTimeout || 600000, timeout: config.requestTimeout || 600000,
signal: abortController.signal, signal: abortController.signal,
validateStatus: () => true // 接受所有状态码 validateStatus: () => true // 接受所有状态码
} }
if (proxyAgent) {
requestConfig.httpAgent = proxyAgent
requestConfig.httpsAgent = proxyAgent
requestConfig.proxy = false
}
// 根据 API Key 格式选择认证方式 // 根据 API Key 格式选择认证方式
if (account.apiKey && account.apiKey.startsWith('sk-ant-')) { if (account.apiKey && account.apiKey.startsWith('sk-ant-')) {
// Anthropic 官方 API Key 使用 x-api-key // Anthropic 官方 API Key 使用 x-api-key
@@ -414,12 +419,17 @@ class ClaudeConsoleRelayService {
'User-Agent': userAgent, 'User-Agent': userAgent,
...filteredHeaders ...filteredHeaders
}, },
httpsAgent: proxyAgent,
timeout: config.requestTimeout || 600000, timeout: config.requestTimeout || 600000,
responseType: 'stream', responseType: 'stream',
validateStatus: () => true // 接受所有状态码 validateStatus: () => true // 接受所有状态码
} }
if (proxyAgent) {
requestConfig.httpAgent = proxyAgent
requestConfig.httpsAgent = proxyAgent
requestConfig.proxy = false
}
// 根据 API Key 格式选择认证方式 // 根据 API Key 格式选择认证方式
if (account.apiKey && account.apiKey.startsWith('sk-ant-')) { if (account.apiKey && account.apiKey.startsWith('sk-ant-')) {
// Anthropic 官方 API Key 使用 x-api-key // Anthropic 官方 API Key 使用 x-api-key

View File

@@ -438,6 +438,7 @@ class DroidAccountService {
if (proxyAgent) { if (proxyAgent) {
requestOptions.httpAgent = proxyAgent requestOptions.httpAgent = proxyAgent
requestOptions.httpsAgent = proxyAgent requestOptions.httpsAgent = proxyAgent
requestOptions.proxy = false
logger.info( logger.info(
`🌐 使用代理验证 Droid Refresh Token: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 使用代理验证 Droid Refresh Token: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )
@@ -506,6 +507,7 @@ class DroidAccountService {
if (proxyAgent) { if (proxyAgent) {
requestOptions.httpAgent = proxyAgent requestOptions.httpAgent = proxyAgent
requestOptions.httpsAgent = proxyAgent requestOptions.httpsAgent = proxyAgent
requestOptions.proxy = false
} }
} }

View File

@@ -309,7 +309,8 @@ class DroidRelayService {
responseType: 'json', responseType: 'json',
...(proxyAgent && { ...(proxyAgent && {
httpAgent: proxyAgent, httpAgent: proxyAgent,
httpsAgent: proxyAgent httpsAgent: proxyAgent,
proxy: false
}) })
} }

View File

@@ -1081,7 +1081,9 @@ async function loadCodeAssist(client, projectId = null, proxyConfig = null) {
} }
if (proxyAgent) { if (proxyAgent) {
tokenInfoConfig.httpAgent = proxyAgent
tokenInfoConfig.httpsAgent = proxyAgent tokenInfoConfig.httpsAgent = proxyAgent
tokenInfoConfig.proxy = false
} }
try { try {
@@ -1102,7 +1104,9 @@ async function loadCodeAssist(client, projectId = null, proxyConfig = null) {
} }
if (proxyAgent) { if (proxyAgent) {
userInfoConfig.httpAgent = proxyAgent
userInfoConfig.httpsAgent = proxyAgent userInfoConfig.httpsAgent = proxyAgent
userInfoConfig.proxy = false
} }
try { try {
@@ -1146,7 +1150,9 @@ async function loadCodeAssist(client, projectId = null, proxyConfig = null) {
// 添加代理配置 // 添加代理配置
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini loadCodeAssist: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 Using proxy for Gemini loadCodeAssist: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )
@@ -1220,7 +1226,9 @@ async function onboardUser(client, tierId, projectId, clientMetadata, proxyConfi
// 添加代理配置 // 添加代理配置
const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig) const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig)
if (proxyAgent) { if (proxyAgent) {
baseAxiosConfig.httpAgent = proxyAgent
baseAxiosConfig.httpsAgent = proxyAgent baseAxiosConfig.httpsAgent = proxyAgent
baseAxiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini onboardUser: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 Using proxy for Gemini onboardUser: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )
@@ -1351,7 +1359,9 @@ async function countTokens(client, contents, model = 'gemini-2.0-flash-exp', pro
// 添加代理配置 // 添加代理配置
const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig) const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini countTokens: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 Using proxy for Gemini countTokens: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )
@@ -1426,7 +1436,9 @@ async function generateContent(
// 添加代理配置 // 添加代理配置
const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig) const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini generateContent: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 Using proxy for Gemini generateContent: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )
@@ -1500,7 +1512,9 @@ async function generateContentStream(
// 添加代理配置 // 添加代理配置
const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig) const proxyAgent = ProxyHelper.createProxyAgent(proxyConfig)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini streamGenerateContent: ${ProxyHelper.getProxyDescription(proxyConfig)}` `🌐 Using proxy for Gemini streamGenerateContent: ${ProxyHelper.getProxyDescription(proxyConfig)}`
) )

View File

@@ -279,7 +279,9 @@ async function sendGeminiRequest({
// 添加代理配置 // 添加代理配置
const proxyAgent = createProxyAgent(proxy) const proxyAgent = createProxyAgent(proxy)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info(`🌐 Using proxy for Gemini API request: ${ProxyHelper.getProxyDescription(proxy)}`) logger.info(`🌐 Using proxy for Gemini API request: ${ProxyHelper.getProxyDescription(proxy)}`)
} else { } else {
logger.debug('🌐 No proxy configured for Gemini API request') logger.debug('🌐 No proxy configured for Gemini API request')
@@ -387,7 +389,9 @@ async function getAvailableModels(accessToken, proxy, projectId, location = 'us-
const proxyAgent = createProxyAgent(proxy) const proxyAgent = createProxyAgent(proxy)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini models request: ${ProxyHelper.getProxyDescription(proxy)}` `🌐 Using proxy for Gemini models request: ${ProxyHelper.getProxyDescription(proxy)}`
) )
@@ -488,7 +492,9 @@ async function countTokens({
// 添加代理配置 // 添加代理配置
const proxyAgent = createProxyAgent(proxy) const proxyAgent = createProxyAgent(proxy)
if (proxyAgent) { if (proxyAgent) {
axiosConfig.httpAgent = proxyAgent
axiosConfig.httpsAgent = proxyAgent axiosConfig.httpsAgent = proxyAgent
axiosConfig.proxy = false
logger.info( logger.info(
`🌐 Using proxy for Gemini countTokens request: ${ProxyHelper.getProxyDescription(proxy)}` `🌐 Using proxy for Gemini countTokens request: ${ProxyHelper.getProxyDescription(proxy)}`
) )

View File

@@ -223,6 +223,7 @@ async function refreshAccessToken(refreshToken, proxy = null) {
// 配置代理(如果有) // 配置代理(如果有)
const proxyAgent = ProxyHelper.createProxyAgent(proxy) const proxyAgent = ProxyHelper.createProxyAgent(proxy)
if (proxyAgent) { if (proxyAgent) {
requestOptions.httpAgent = proxyAgent
requestOptions.httpsAgent = proxyAgent requestOptions.httpsAgent = proxyAgent
requestOptions.proxy = false requestOptions.proxy = false
logger.info( logger.info(

View File

@@ -107,6 +107,7 @@ class OpenAIResponsesRelayService {
if (fullAccount.proxy) { if (fullAccount.proxy) {
const proxyAgent = ProxyHelper.createProxyAgent(fullAccount.proxy) const proxyAgent = ProxyHelper.createProxyAgent(fullAccount.proxy)
if (proxyAgent) { if (proxyAgent) {
requestOptions.httpAgent = proxyAgent
requestOptions.httpsAgent = proxyAgent requestOptions.httpsAgent = proxyAgent
requestOptions.proxy = false requestOptions.proxy = false
logger.info( logger.info(

View File

@@ -173,7 +173,7 @@ async function exchangeCodeForTokens(authorizationCode, codeVerifier, state, pro
proxyType: proxyConfig?.type || 'none' proxyType: proxyConfig?.type || 'none'
}) })
const response = await axios.post(OAUTH_CONFIG.TOKEN_URL, params, { const axiosConfig = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'User-Agent': 'claude-cli/1.0.56 (external, cli)', 'User-Agent': 'claude-cli/1.0.56 (external, cli)',
@@ -182,9 +182,16 @@ async function exchangeCodeForTokens(authorizationCode, codeVerifier, state, pro
Referer: 'https://claude.ai/', Referer: 'https://claude.ai/',
Origin: 'https://claude.ai' Origin: 'https://claude.ai'
}, },
httpsAgent: agent,
timeout: 30000 timeout: 30000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.post(OAUTH_CONFIG.TOKEN_URL, params, axiosConfig)
// 记录完整的响应数据到专门的认证详细日志 // 记录完整的响应数据到专门的认证详细日志
logger.authDetail('OAuth token exchange response', response.data) logger.authDetail('OAuth token exchange response', response.data)
@@ -378,7 +385,7 @@ async function exchangeSetupTokenCode(authorizationCode, codeVerifier, state, pr
proxyType: proxyConfig?.type || 'none' proxyType: proxyConfig?.type || 'none'
}) })
const response = await axios.post(OAUTH_CONFIG.TOKEN_URL, params, { const axiosConfig = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'User-Agent': 'claude-cli/1.0.56 (external, cli)', 'User-Agent': 'claude-cli/1.0.56 (external, cli)',
@@ -387,9 +394,16 @@ async function exchangeSetupTokenCode(authorizationCode, codeVerifier, state, pr
Referer: 'https://claude.ai/', Referer: 'https://claude.ai/',
Origin: 'https://claude.ai' Origin: 'https://claude.ai'
}, },
httpsAgent: agent,
timeout: 30000 timeout: 30000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.post(OAUTH_CONFIG.TOKEN_URL, params, axiosConfig)
// 记录完整的响应数据到专门的认证详细日志 // 记录完整的响应数据到专门的认证详细日志
logger.authDetail('Setup Token exchange response', response.data) logger.authDetail('Setup Token exchange response', response.data)

View File

@@ -40,13 +40,20 @@ async function startDeviceAuthorization(proxyConfig = null) {
hasProxy: !!agent hasProxy: !!agent
}) })
const response = await axios.post(WORKOS_DEVICE_AUTHORIZE_URL, form.toString(), { const axiosConfig = {
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
httpsAgent: agent,
timeout: 15000 timeout: 15000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.post(WORKOS_DEVICE_AUTHORIZE_URL, form.toString(), axiosConfig)
const data = response.data || {} const data = response.data || {}
@@ -108,13 +115,20 @@ async function pollDeviceAuthorization(deviceCode, proxyConfig = null) {
const agent = ProxyHelper.createProxyAgent(proxyConfig) const agent = ProxyHelper.createProxyAgent(proxyConfig)
try { try {
const response = await axios.post(WORKOS_TOKEN_URL, form.toString(), { const axiosConfig = {
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
httpsAgent: agent,
timeout: 15000 timeout: 15000
}) }
if (agent) {
axiosConfig.httpAgent = agent
axiosConfig.httpsAgent = agent
axiosConfig.proxy = false
}
const response = await axios.post(WORKOS_TOKEN_URL, form.toString(), axiosConfig)
const data = response.data || {} const data = response.data || {}