feat(accounts): support header overrides for CN providers

This commit is contained in:
wucm667
2026-08-19 19:03:39 +08:00
parent ae62854abc
commit 1b30a2d747
8 changed files with 51 additions and 14 deletions
@@ -9,8 +9,8 @@ import (
"golang.org/x/net/http/httpguts"
)
// 请求头覆写(header override):对 Anthropic / OpenAI 平台的 api_key 账号
// 以及 Grok 平台的 api_key / oauth 账号生效。
// 请求头覆写(header override):对 Anthropic / OpenAI / Kimi / Zhipu / DeepSeek
// 平台的 api_key 账号,以及 Grok 平台的 api_key / oauth 账号生效。
// 管理员在账号上配置一组 header name -> value,转发到上游前用配置值覆盖同名请求头
// (匹配不区分大小写);value 为空的条目视为"未填写",不参与覆盖。
const (
@@ -70,14 +70,15 @@ func isHeaderOverrideBlockedName(lowerName string) bool {
}
// IsHeaderOverrideEligible 报告账号类型是否支持请求头覆写。
// Anthropic / OpenAI 仅开放 api_key 账号;Grok 额外开放 oauth 账号——
// Anthropic / OpenAI / Kimi / Zhipu / DeepSeek 仅开放 api_key 账号;
// Grok 额外开放 oauth 账号——
// 订阅流量改发自定义转发地址时,通常需要补充中间层要求的准入头。
func (a *Account) IsHeaderOverrideEligible() bool {
if a == nil {
return false
}
switch a.Platform {
case PlatformAnthropic, PlatformOpenAI:
case PlatformAnthropic, PlatformOpenAI, PlatformKimi, PlatformZhipu, PlatformDeepseek:
return a.Type == AccountTypeAPIKey
case PlatformGrok:
return a.Type == AccountTypeAPIKey || a.Type == AccountTypeOAuth
@@ -27,8 +27,14 @@ func TestIsHeaderOverrideEligible(t *testing.T) {
}{
{"anthropic apikey", PlatformAnthropic, AccountTypeAPIKey, true},
{"openai apikey", PlatformOpenAI, AccountTypeAPIKey, true},
{"kimi apikey", PlatformKimi, AccountTypeAPIKey, true},
{"zhipu apikey", PlatformZhipu, AccountTypeAPIKey, true},
{"deepseek apikey", PlatformDeepseek, AccountTypeAPIKey, true},
{"anthropic oauth", PlatformAnthropic, AccountTypeOAuth, false},
{"openai oauth", PlatformOpenAI, AccountTypeOAuth, false},
{"kimi oauth", PlatformKimi, AccountTypeOAuth, false},
{"zhipu oauth", PlatformZhipu, AccountTypeOAuth, false},
{"deepseek oauth", PlatformDeepseek, AccountTypeOAuth, false},
{"gemini apikey", PlatformGemini, AccountTypeAPIKey, false},
{"grok apikey", PlatformGrok, AccountTypeAPIKey, true},
{"grok oauth", PlatformGrok, AccountTypeOAuth, true},
@@ -602,7 +602,7 @@
</div>
</div>
<!-- Header Override (anthropic/openai apikey only) -->
<!-- Header Override (eligible API-key platforms + grok OAuth) -->
<div v-if="allHeaderOverrideCapable" class="border-t border-gray-200 pt-4 dark:border-dark-600">
<div class="flex items-center justify-between">
<div class="flex-1 pr-4">
@@ -1599,7 +1599,7 @@ const allBillingProbeCapable = computed(() => {
)
})
// 是否全部为 anthropic/openai 平台的 apikey 账号(请求头覆写仅在此条件下显示)
// 是否全部为支持请求头覆写的平台/账号类型
// 所选平台 × 所选类型的全组合均需具备覆写资格(实际选中账号是该组合的子集,
// 按交叉积判定偏保守但绝不放行不合资格的账号)
const allHeaderOverrideCapable = computed(() => {
@@ -1661,7 +1661,7 @@
</div>
</div>
<!-- Header Override Section (anthropic/openai apikey only) -->
<!-- Header Override Section (eligible API-key platforms) -->
<div
v-if="isHeaderOverrideCapable(form.platform, 'apikey')"
class="border-t border-gray-200 pt-4 dark:border-dark-600"
@@ -5458,7 +5458,7 @@ const handleSubmit = async () => {
credentials.custom_error_codes = [...selectedErrorCodes.value]
}
// Add header override if enabled (anthropic/openai/grok apikey)
// Add header override if enabled for this API-key platform
if (isHeaderOverrideCapable(form.platform, 'apikey')) {
if (headerOverrideEnabled.value) {
const headerError = validateHeaderOverrideRows(headerOverrideRows.value)
@@ -540,7 +540,7 @@
</div>
</div>
<!-- Header Override Section (anthropic/openai apikey + grok apikey/oauth) -->
<!-- Header Override Section (eligible API-key platforms + grok OAuth) -->
<div v-if="headerOverrideCapable" class="border-t border-gray-200 pt-4 dark:border-dark-600">
<div class="mb-3 flex items-center justify-between">
<div>
@@ -3730,7 +3730,7 @@ const syncFormFromAccount = (newAccount: Account | null) => {
loadTempUnschedRules(credentials)
loadAccountSchedulingThresholdOverride(newAccount.platform, credentials)
// Load header override state (anthropic/openai apikey + grok apikey/oauth)
// Load header override state for eligible account platforms/types
headerOverrideEnabled.value = false
headerOverrideRows.value = []
if (newAccount.credentials && isHeaderOverrideCapable(newAccount.platform, newAccount.type)) {
@@ -4520,7 +4520,7 @@ const handleSubmit = async () => {
delete newCredentials.custom_error_codes
}
// Add header override if enabled (anthropic/openai/grok apikey)
// Add header override if enabled for this API-key platform
if (isHeaderOverrideCapable(props.account.platform, 'apikey')) {
if (headerOverrideEnabled.value) {
const headerError = validateHeaderOverrideRows(headerOverrideRows.value)
@@ -217,6 +217,24 @@ describe('BulkEditAccountModal', () => {
expect(wrapper.findAll('[data-testid="grok-base-url-preset"]').length).toBe(0)
})
it.each(['kimi', 'zhipu', 'deepseek'])('全部目标为 %s API Key 时展示请求头覆写', (platform) => {
const wrapper = mountModal({
selectedPlatforms: [platform],
selectedTypes: ['apikey']
})
expect(wrapper.find('#bulk-edit-header-override-enabled').exists()).toBe(true)
})
it.each(['kimi', 'zhipu', 'deepseek'])('目标为 %s OAuth 时不展示请求头覆写', (platform) => {
const wrapper = mountModal({
selectedPlatforms: [platform],
selectedTypes: ['oauth']
})
expect(wrapper.find('#bulk-edit-header-override-enabled').exists()).toBe(false)
})
it('全部目标为 Grok OAuth 时,第三方 base_url 正常提交', async () => {
const wrapper = mountModal({
selectedPlatforms: ['grok'],
@@ -106,6 +106,13 @@ describe('isHeaderOverrideCapable', () => {
expect(isHeaderOverrideCapable('openai', 'oauth')).toBe(false)
})
it('kimi/zhipu/deepseek only support apikey accounts', () => {
for (const platform of ['kimi', 'zhipu', 'deepseek']) {
expect(isHeaderOverrideCapable(platform, 'apikey')).toBe(true)
expect(isHeaderOverrideCapable(platform, 'oauth')).toBe(false)
}
})
it('grok supports both apikey and oauth accounts', () => {
expect(isHeaderOverrideCapable('grok', 'apikey')).toBe(true)
expect(isHeaderOverrideCapable('grok', 'oauth')).toBe(true)
@@ -468,4 +475,3 @@ describe('plan_type helpers', () => {
})
})
})
@@ -25,7 +25,7 @@ export function applyAntigravityProjectID(
}
}
// ========== 请求头覆写(anthropic/openai 的 api_key 账号 + grok 的 api_key/oauth 账号) ==========
// ========== 请求头覆写(API-key 平台 + grok 的 api_key/oauth 账号) ==========
export const HEADER_OVERRIDE_ENABLED_CREDENTIAL_KEY = 'header_override_enabled'
export const HEADER_OVERRIDES_CREDENTIAL_KEY = 'header_overrides'
@@ -37,7 +37,13 @@ export interface HeaderOverrideRow {
/** 请求头覆写资格(与后端 IsHeaderOverrideEligible 保持一致) */
export function isHeaderOverrideCapable(platform: string, type: string): boolean {
if (platform === 'anthropic' || platform === 'openai') {
if (
platform === 'anthropic' ||
platform === 'openai' ||
platform === 'kimi' ||
platform === 'zhipu' ||
platform === 'deepseek'
) {
return type === 'apikey'
}
if (platform === 'grok') {