From 3bf37cf0ff5dbb8157d29ef4c98b68dedd1d6658 Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 29 Nov 2025 20:52:29 +0800 Subject: [PATCH] refactor(url): remove automatic trailing slash stripping from base URL inputs - Remove `.replace(/\/+$/, "")` from all base URL handlers in useBaseUrlState.ts - Remove trailing slash stripping in useCodexConfigState.ts - Remove trailing slash normalization in providerConfigUtils.ts setCodexBaseUrl() - Update i18n hints (en/ja/zh) to instruct users to avoid trailing slashes This gives users explicit control over URL format rather than silently modifying input. --- .../providers/forms/hooks/useBaseUrlState.ts | 11 +++++------ .../providers/forms/hooks/useCodexConfigState.ts | 2 +- src/i18n/locales/en.json | 2 +- src/i18n/locales/ja.json | 2 +- src/i18n/locales/zh.json | 2 +- src/utils/providerConfigUtils.ts | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/components/providers/forms/hooks/useBaseUrlState.ts b/src/components/providers/forms/hooks/useBaseUrlState.ts index 8a5a25a4c..61b1ad997 100644 --- a/src/components/providers/forms/hooks/useBaseUrlState.ts +++ b/src/components/providers/forms/hooks/useBaseUrlState.ts @@ -41,7 +41,7 @@ export function useBaseUrlState({ try { const config = JSON.parse(settingsConfig || "{}"); const envUrl: unknown = config?.env?.ANTHROPIC_BASE_URL; - if (typeof envUrl === "string" && envUrl && envUrl !== baseUrl) { + if (typeof envUrl === "string" && envUrl && envUrl.trim() !== baseUrl) { setBaseUrl(envUrl.trim()); } } catch { @@ -73,8 +73,7 @@ export function useBaseUrlState({ try { const config = JSON.parse(settingsConfig || "{}"); const envUrl: unknown = config?.env?.GOOGLE_GEMINI_BASE_URL; - const nextUrl = - typeof envUrl === "string" ? envUrl.trim().replace(/\/+$/, "") : ""; + const nextUrl = typeof envUrl === "string" ? envUrl.trim() : ""; if (nextUrl !== geminiBaseUrl) { setGeminiBaseUrl(nextUrl); setBaseUrl(nextUrl); // 也更新 baseUrl 用于 UI @@ -87,7 +86,7 @@ export function useBaseUrlState({ // 处理 Claude Base URL 变化 const handleClaudeBaseUrlChange = useCallback( (url: string) => { - const sanitized = url.trim().replace(/\/+$/, ""); + const sanitized = url.trim(); setBaseUrl(sanitized); isUpdatingRef.current = true; @@ -112,7 +111,7 @@ export function useBaseUrlState({ // 处理 Codex Base URL 变化 const handleCodexBaseUrlChange = useCallback( (url: string) => { - const sanitized = url.trim().replace(/\/+$/, ""); + const sanitized = url.trim(); setCodexBaseUrl(sanitized); if (!sanitized || !onCodexConfigChange) { @@ -136,7 +135,7 @@ export function useBaseUrlState({ // 处理 Gemini Base URL 变化 const handleGeminiBaseUrlChange = useCallback( (url: string) => { - const sanitized = url.trim().replace(/\/+$/, ""); + const sanitized = url.trim(); setGeminiBaseUrl(sanitized); setBaseUrl(sanitized); // 也更新 baseUrl 用于 UI isUpdatingRef.current = true; diff --git a/src/components/providers/forms/hooks/useCodexConfigState.ts b/src/components/providers/forms/hooks/useCodexConfigState.ts index 60436a04e..a4271c067 100644 --- a/src/components/providers/forms/hooks/useCodexConfigState.ts +++ b/src/components/providers/forms/hooks/useCodexConfigState.ts @@ -162,7 +162,7 @@ export function useCodexConfigState({ initialData }: UseCodexConfigStateProps) { // 处理 Codex Base URL 变化 const handleCodexBaseUrlChange = useCallback( (url: string) => { - const sanitized = url.trim().replace(/\/+$/, ""); + const sanitized = url.trim(); setCodexBaseUrl(sanitized); if (!sanitized) { diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 1e2f26b34..92820c5ab 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -272,7 +272,7 @@ "fastModel": "Fast Model (optional)", "fastModelPlaceholder": "e.g., GLM-4.5-Air", "modelHint": "💡 Leave blank to use provider's default model", - "apiHint": "💡 Fill in Claude API compatible service endpoint", + "apiHint": "💡 Fill in Claude API compatible service endpoint, avoid trailing slash", "codexApiHint": "💡 Fill in service endpoint compatible with OpenAI Response format", "fillSupplierName": "Please fill in provider name", "fillConfigContent": "Please fill in configuration content", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index abc800a46..0fab2caa1 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -272,7 +272,7 @@ "fastModel": "高速モデル(任意)", "fastModelPlaceholder": "例: GLM-4.5-Air", "modelHint": "💡 空欄ならプロバイダーのデフォルトモデルを使用します", - "apiHint": "💡 Claude API 互換サービスのエンドポイントを入力してください", + "apiHint": "💡 Claude API 互換サービスのエンドポイントを入力してください。末尾にスラッシュを付けないでください", "codexApiHint": "💡 OpenAI Response 互換のサービスエンドポイントを入力してください", "fillSupplierName": "プロバイダー名を入力してください", "fillConfigContent": "設定内容を入力してください", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index d6c4c85eb..6eacfbfde 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -272,7 +272,7 @@ "fastModel": "快速模型 (可选)", "fastModelPlaceholder": "例如: GLM-4.5-Air", "modelHint": "💡 留空将使用供应商的默认模型", - "apiHint": "💡 填写兼容 Claude API 的服务端点地址", + "apiHint": "💡 填写兼容 Claude API 的服务端点地址,不要以斜杠结尾", "codexApiHint": "💡 填写兼容 OpenAI Response 格式的服务端点地址", "fillSupplierName": "请填写供应商名称", "fillConfigContent": "请填写配置内容", diff --git a/src/utils/providerConfigUtils.ts b/src/utils/providerConfigUtils.ts index e2e73a1b4..6658a2333 100644 --- a/src/utils/providerConfigUtils.ts +++ b/src/utils/providerConfigUtils.ts @@ -453,7 +453,7 @@ export const setCodexBaseUrl = ( // 归一化原文本中的引号(既能匹配,也能输出稳定格式) const normalizedText = normalizeQuotes(configText); - const normalizedUrl = trimmed.replace(/\s+/g, "").replace(/\/+$/, ""); + const normalizedUrl = trimmed.replace(/\s+/g, ""); const replacementLine = `base_url = "${normalizedUrl}"`; const pattern = /base_url\s*=\s*(["'])([^"']+)\1/;