Merge pull request #411 from bottotl/main

兼容 sider 自定义 API
This commit is contained in:
Wesley Liddick
2025-09-10 22:36:54 +08:00
committed by GitHub
4 changed files with 89 additions and 6 deletions

View File

@@ -34,6 +34,7 @@ const {
globalRateLimit, globalRateLimit,
requestSizeLimit requestSizeLimit
} = require('./middleware/auth') } = require('./middleware/auth')
const { browserFallbackMiddleware } = require('./middleware/browserFallback')
class Application { class Application {
constructor() { constructor() {
@@ -109,6 +110,9 @@ class Application {
this.app.use(corsMiddleware) this.app.use(corsMiddleware)
} }
// 🆕 兜底中间件处理Chrome插件兼容性必须在认证之前
this.app.use(browserFallbackMiddleware)
// 📦 压缩 - 排除流式响应SSE // 📦 压缩 - 排除流式响应SSE
this.app.use( this.app.use(
compression({ compression({

View File

@@ -757,7 +757,7 @@ const requireAdmin = (req, res, next) => {
// 注意:使用统计现在直接在/api/v1/messages路由中处理 // 注意:使用统计现在直接在/api/v1/messages路由中处理
// 以便从Claude API响应中提取真实的usage数据 // 以便从Claude API响应中提取真实的usage数据
// 🚦 CORS中间件优化版 // 🚦 CORS中间件优化版支持Chrome插件
const corsMiddleware = (req, res, next) => { const corsMiddleware = (req, res, next) => {
const { origin } = req.headers const { origin } = req.headers
@@ -769,8 +769,11 @@ const corsMiddleware = (req, res, next) => {
'https://127.0.0.1:3000' 'https://127.0.0.1:3000'
] ]
// 🆕 检查是否为Chrome插件请求
const isChromeExtension = origin && origin.startsWith('chrome-extension://')
// 设置CORS头 // 设置CORS头
if (allowedOrigins.includes(origin) || !origin) { if (allowedOrigins.includes(origin) || !origin || isChromeExtension) {
res.header('Access-Control-Allow-Origin', origin || '*') res.header('Access-Control-Allow-Origin', origin || '*')
} }
@@ -785,7 +788,9 @@ const corsMiddleware = (req, res, next) => {
'Authorization', 'Authorization',
'x-api-key', 'x-api-key',
'api-key', 'api-key',
'x-admin-token' 'x-admin-token',
'anthropic-version',
'anthropic-dangerous-direct-browser-access'
].join(', ') ].join(', ')
) )

View File

@@ -0,0 +1,52 @@
const logger = require('../utils/logger')
/**
* 浏览器/Chrome插件兜底中间件
* 专门处理第三方插件的兼容性问题
*/
const browserFallbackMiddleware = (req, res, next) => {
const userAgent = req.headers['user-agent'] || ''
const origin = req.headers['origin'] || ''
const authHeader = req.headers['authorization'] || req.headers['x-api-key'] || ''
// 检查是否为Chrome插件或浏览器请求
const isChromeExtension = origin.startsWith('chrome-extension://')
const isBrowserRequest = userAgent.includes('Mozilla/') && userAgent.includes('Chrome/')
const hasApiKey = authHeader.startsWith('cr_') // 我们的API Key格式
if ((isChromeExtension || isBrowserRequest) && hasApiKey) {
// 为Chrome插件请求添加特殊标记
req.isBrowserFallback = true
req.originalUserAgent = userAgent
// 🆕 关键修改伪装成claude-cli请求以绕过客户端限制
req.headers['user-agent'] = 'claude-cli/1.0.110 (external, cli, browser-fallback)'
// 确保设置正确的认证头
if (!req.headers['authorization'] && req.headers['x-api-key']) {
req.headers['authorization'] = `Bearer ${req.headers['x-api-key']}`
}
// 添加必要的Anthropic头
if (!req.headers['anthropic-version']) {
req.headers['anthropic-version'] = '2023-06-01'
}
if (!req.headers['anthropic-dangerous-direct-browser-access']) {
req.headers['anthropic-dangerous-direct-browser-access'] = 'true'
}
logger.api(
`🔧 Browser fallback activated for ${isChromeExtension ? 'Chrome extension' : 'browser'} request`
)
logger.api(` Original User-Agent: "${req.originalUserAgent}"`)
logger.api(` Origin: "${origin}"`)
logger.api(` Modified User-Agent: "${req.headers['user-agent']}"`)
}
next()
}
module.exports = {
browserFallbackMiddleware
}

View File

@@ -629,8 +629,30 @@ class ClaudeRelayService {
'transfer-encoding' 'transfer-encoding'
] ]
// 🆕 需要移除的浏览器相关 headers避免CORS问题
const browserHeaders = [
'origin',
'referer',
'sec-fetch-mode',
'sec-fetch-site',
'sec-fetch-dest',
'sec-ch-ua',
'sec-ch-ua-mobile',
'sec-ch-ua-platform',
'accept-language',
'accept-encoding',
'accept',
'cache-control',
'pragma',
'anthropic-dangerous-direct-browser-access' // 这个头可能触发CORS检查
]
// 应该保留的 headers用于会话一致性和追踪 // 应该保留的 headers用于会话一致性和追踪
const allowedHeaders = ['x-request-id'] const allowedHeaders = [
'x-request-id',
'anthropic-version', // 保留API版本
'anthropic-beta' // 保留beta功能
]
const filteredHeaders = {} const filteredHeaders = {}
@@ -641,8 +663,8 @@ class ClaudeRelayService {
if (allowedHeaders.includes(lowerKey)) { if (allowedHeaders.includes(lowerKey)) {
filteredHeaders[key] = clientHeaders[key] filteredHeaders[key] = clientHeaders[key]
} }
// 如果不在敏感列表中,也保留 // 如果不在敏感列表和浏览器列表中,也保留
else if (!sensitiveHeaders.includes(lowerKey)) { else if (!sensitiveHeaders.includes(lowerKey) && !browserHeaders.includes(lowerKey)) {
filteredHeaders[key] = clientHeaders[key] filteredHeaders[key] = clientHeaders[key]
} }
}) })