feat: 网关请求头 wire casing 保持、转发行为开关、调试日志增强及 accept-encoding 恢复
- 新增 header_util.go,通过 setHeaderRaw/getHeaderRaw/addHeaderRaw 绕过 Go 的 canonical-case 规范化,保持真实 Claude CLI 抓包的请求头大小写 (如 "x-app" 而非 "X-App","X-Stainless-OS" 而非 "X-Stainless-Os") - 新增管理后台开关:指纹统一化(默认开启)和 metadata 透传(默认关闭), 使用 atomic.Value + singleflight 缓存模式,60s TTL - 调试日志从控制台 body 打印升级为文件级完整快照 (按真实 wire 顺序输出 headers + 格式化 JSON body + 上下文元数据) - 恢复 accept-encoding 到白名单,在 http_upstream.go 新增 decompressResponseBody 处理 gzip/brotli/deflate 解压(Go 显式设置 Accept-Encoding 时不会自动解压) - OAuth 服务 axios UA 从 1.8.4 更新至 1.13.6 - 测试断言改用 getHeaderRaw 适配 raw header 存储方式
This commit is contained in:
@@ -86,6 +86,10 @@ export interface SystemSettings {
|
||||
|
||||
// 分组隔离
|
||||
allow_ungrouped_key_scheduling: boolean
|
||||
|
||||
// Gateway forwarding behavior
|
||||
enable_fingerprint_unification: boolean
|
||||
enable_metadata_passthrough: boolean
|
||||
}
|
||||
|
||||
export interface UpdateSettingsRequest {
|
||||
@@ -142,6 +146,8 @@ export interface UpdateSettingsRequest {
|
||||
min_claude_code_version?: string
|
||||
max_claude_code_version?: string
|
||||
allow_ungrouped_key_scheduling?: boolean
|
||||
enable_fingerprint_unification?: boolean
|
||||
enable_metadata_passthrough?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4171,6 +4171,14 @@ export default {
|
||||
allowUngroupedKey: 'Allow Ungrouped Key Scheduling',
|
||||
allowUngroupedKeyHint: 'When disabled, API Keys not assigned to any group cannot make requests (403 Forbidden). Keep disabled to ensure all Keys belong to a specific group.'
|
||||
},
|
||||
gatewayForwarding: {
|
||||
title: 'Request Forwarding',
|
||||
description: 'Control how requests are forwarded to upstream OAuth accounts',
|
||||
fingerprintUnification: 'Fingerprint Unification',
|
||||
fingerprintUnificationHint: 'Unify X-Stainless-* headers across users sharing the same OAuth account. Disabling passes through each client\'s original headers.',
|
||||
metadataPassthrough: 'Metadata Passthrough',
|
||||
metadataPassthroughHint: 'Pass through client\'s original metadata.user_id without rewriting. May improve upstream cache hit rates.',
|
||||
},
|
||||
site: {
|
||||
title: 'Site Settings',
|
||||
description: 'Customize site branding',
|
||||
|
||||
@@ -4334,6 +4334,14 @@ export default {
|
||||
allowUngroupedKey: '允许未分组 Key 调度',
|
||||
allowUngroupedKeyHint: '关闭后,未分配到任何分组的 API Key 将无法发起请求(返回 403)。建议保持关闭以确保所有 Key 都归属明确的分组。'
|
||||
},
|
||||
gatewayForwarding: {
|
||||
title: '请求转发行为',
|
||||
description: '控制请求转发到上游 OAuth 账号时的行为',
|
||||
fingerprintUnification: '指纹统一化',
|
||||
fingerprintUnificationHint: '统一共享同一 OAuth 账号的用户的 X-Stainless-* 请求头。关闭后透传客户端原始请求头。',
|
||||
metadataPassthrough: 'Metadata 透传',
|
||||
metadataPassthroughHint: '透传客户端原始 metadata.user_id,不进行重写。可能提高上游缓存命中率。',
|
||||
},
|
||||
site: {
|
||||
title: '站点设置',
|
||||
description: '自定义站点品牌',
|
||||
|
||||
@@ -1171,6 +1171,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gateway Forwarding Behavior -->
|
||||
<div class="card">
|
||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.settings.gatewayForwarding.title') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.gatewayForwarding.description') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-5 p-6">
|
||||
<!-- Fingerprint Unification -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.gatewayForwarding.fingerprintUnification') }}
|
||||
</label>
|
||||
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.gatewayForwarding.fingerprintUnificationHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="form.enable_fingerprint_unification" />
|
||||
</div>
|
||||
|
||||
<!-- Metadata Passthrough -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.gatewayForwarding.metadataPassthrough') }}
|
||||
</label>
|
||||
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.gatewayForwarding.metadataPassthroughHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="form.enable_metadata_passthrough" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /Tab: Gateway — Claude Code, Scheduling -->
|
||||
|
||||
<!-- Tab: General -->
|
||||
@@ -2066,7 +2105,10 @@ const form = reactive<SettingsForm>({
|
||||
min_claude_code_version: '',
|
||||
max_claude_code_version: '',
|
||||
// 分组隔离
|
||||
allow_ungrouped_key_scheduling: false
|
||||
allow_ungrouped_key_scheduling: false,
|
||||
// Gateway forwarding behavior
|
||||
enable_fingerprint_unification: true,
|
||||
enable_metadata_passthrough: false
|
||||
})
|
||||
|
||||
const defaultSubscriptionGroupOptions = computed<DefaultSubscriptionGroupOption[]>(() =>
|
||||
@@ -2373,7 +2415,9 @@ async function saveSettings() {
|
||||
identity_patch_prompt: form.identity_patch_prompt,
|
||||
min_claude_code_version: form.min_claude_code_version,
|
||||
max_claude_code_version: form.max_claude_code_version,
|
||||
allow_ungrouped_key_scheduling: form.allow_ungrouped_key_scheduling
|
||||
allow_ungrouped_key_scheduling: form.allow_ungrouped_key_scheduling,
|
||||
enable_fingerprint_unification: form.enable_fingerprint_unification,
|
||||
enable_metadata_passthrough: form.enable_metadata_passthrough
|
||||
}
|
||||
const updated = await adminAPI.settings.updateSettings(payload)
|
||||
Object.assign(form, updated)
|
||||
|
||||
Reference in New Issue
Block a user