From 2a5167790867769dd709c78ada0c258dfba3c8bb Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Wed, 9 Sep 2026 12:53:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BC=80=E5=8F=91=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E9=81=BF=E5=85=8D=20CORS=EF=BC=8Cideship=20Track=20=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=8E=BB=E9=87=8D=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本地开发改为同源代理到生产/测试 API;ideship 将 /Track/Track 归一为 /track/Track,避免 404。 Co-authored-by: Cursor --- .env.development | 11 ++----- .env.ideship | 8 ++---- .env.nanafa | 4 +-- src/utils/adminApi.ts | 42 +++++++++++---------------- src/utils/rewriteBrowserApiPath.ts | 22 ++++++++++++-- vite.config.ts | 46 +++++++++++++++++++++++------- 6 files changed, 79 insertions(+), 54 deletions(-) diff --git a/.env.development b/.env.development index c657137..fe20139 100644 --- a/.env.development +++ b/.env.development @@ -1,18 +1,13 @@ # ============================================================================= -# 本地开发默认 → 测试环境 oms.nanafa.com / api.nanafa.com -# 切换到生产 API:pnpm dev:ideship (加载 .env.ideship) -# 发版构建:pnpm build(生产) / pnpm build:test(测试) +# 本地开发默认 → 测试环境(Vite 代理到 api.nanafa.com,无浏览器 CORS) +# 切生产:pnpm dev:ideship # ============================================================================= VITE_DEPLOY_TARGET=nanafa -VITE_API_ORIGIN=http://api.nanafa.com -VITE_API_ADMIN_URL=http://api.nanafa.com/admin VITE_OMS_ADMIN_URL=http://api.nanafa.com/admin -VITE_API_ASSET_ORIGIN=http://api.nanafa.com/admin +VITE_API_ORIGIN=http://api.nanafa.com -# 企业微信客服 VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a -# 智谱 AI(接口映射脚本生成) VITE_ZHIPU_API_KEY=85bbbef6bafd4ca383eef04189decd07.lKVQHcLGtYE8oUn5 VITE_ZHIPU_BASE_URL=/zhipu-api VITE_ZHIPU_MODEL=glm-5.1 diff --git a/.env.ideship b/.env.ideship index 743f66b..3a538dd 100644 --- a/.env.ideship +++ b/.env.ideship @@ -1,11 +1,9 @@ # ============================================================================= -# 本地开发直连生产 API(ideship.com)— pnpm dev:ideship -# 仅用于联调生产;正式发版请用 pnpm build(.env.production) +# 本地开发直连生产 API(ideship)— pnpm dev:ideship +# 浏览器仍请求 localhost,由 Vite 代理到 api.ideship.com(避免 CORS) # ============================================================================= VITE_DEPLOY_TARGET=ideship -VITE_API_ORIGIN=https://api.ideship.com -VITE_API_ADMIN_URL=https://api.ideship.com/admin VITE_OMS_ADMIN_URL=https://api.ideship.com/admin -VITE_API_ASSET_ORIGIN=https://api.ideship.com/admin +VITE_API_ORIGIN=https://api.ideship.com VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a diff --git a/.env.nanafa b/.env.nanafa index c0a7af9..306042e 100644 --- a/.env.nanafa +++ b/.env.nanafa @@ -1,7 +1,5 @@ # ============================================================================= -# 测试环境(oms.nanafa.com)— pnpm build:test → vite build --mode nanafa -# 三套 API:http://api.nanafa.com/{admin|itfx|track} -# 前端站点:https://oms.nanafa.com +# 测试环境构建(oms.nanafa.com)— pnpm build:test # ============================================================================= VITE_DEPLOY_TARGET=nanafa VITE_API_ORIGIN=http://api.nanafa.com diff --git a/src/utils/adminApi.ts b/src/utils/adminApi.ts index 3b6a7ae..996538a 100644 --- a/src/utils/adminApi.ts +++ b/src/utils/adminApi.ts @@ -1,8 +1,7 @@ /** * Admin API 地址(方案 A) - * - 优先 VITE_API_ADMIN_URL(.env.production / .env.nanafa / .env.ideship 切换) - * - 未配置且开发:相对路径走 Vite 代理 - * - 未配置且生产构建:默认 https://api.ideship.com/admin + * - 开发:始终相对路径,由 Vite 代理到 VITE_OMS_ADMIN_URL(避免 localhost→api 跨域) + * - 生产构建:VITE_API_ADMIN_URL / 默认 https://api.ideship.com/admin */ function normalizeBase(base: string): string { @@ -22,34 +21,27 @@ function configuredAdminBase(): string | undefined { return undefined } -function prodAdminBase(): string { - return configuredAdminBase() ?? DEFAULT_PROD_ADMIN -} - /** 浏览器请求 Admin API(OpenAPI.BASE 或 omsUrl/orderUrl 等) */ export function resolveAdminApiPath(path: string): string { const p = ensureLeadingSlash(path) - const configured = configuredAdminBase() - if (configured) { - return `${configured}${p}` + // 开发走同源代理,不直连远程(生产 CORS 不放行 localhost) + if (import.meta.env.DEV) { + return p } - if (!import.meta.env.DEV) { - return `${DEFAULT_PROD_ADMIN}${p}` - } - return p + return `${configuredAdminBase() ?? DEFAULT_PROD_ADMIN}${p}` } export function resolveOpenApiBase(): string { - const configured = configuredAdminBase() - if (configured) return configured - if (!import.meta.env.DEV) { - return DEFAULT_PROD_ADMIN + if (import.meta.env.DEV) { + return '' } - return '' + return configuredAdminBase() ?? DEFAULT_PROD_ADMIN } -/** 桌面 Agent 等直连 Admin 网关 */ +/** 桌面 Agent 等直连 Admin 网关(不受浏览器 CORS 限制) */ export function resolveDirectAdminApiUrl(): string { + const fromOms = import.meta.env.VITE_OMS_ADMIN_URL as string | undefined + if (fromOms?.trim()) return normalizeBase(fromOms) const configured = configuredAdminBase() if (configured) return configured if (import.meta.env.DEV) { @@ -60,14 +52,12 @@ export function resolveDirectAdminApiUrl(): string { /** 静态资源(uploads)在 Admin wwwroot,须带 `/admin`。 */ export function resolveAdminAssetOrigin(): string { + if (import.meta.env.DEV) { + return '' + } const override = import.meta.env.VITE_API_ASSET_ORIGIN as string | undefined if (override?.trim()) { return normalizeBase(override) } - const configured = configuredAdminBase() - if (configured) return configured - if (!import.meta.env.DEV) { - return DEFAULT_PROD_ADMIN - } - return '' + return configuredAdminBase() ?? DEFAULT_PROD_ADMIN } diff --git a/src/utils/rewriteBrowserApiPath.ts b/src/utils/rewriteBrowserApiPath.ts index 29f796b..964430f 100644 --- a/src/utils/rewriteBrowserApiPath.ts +++ b/src/utils/rewriteBrowserApiPath.ts @@ -20,9 +20,10 @@ const SPA_API_PREFIXES = [ const DEFAULT_PROD_API = 'https://api.ideship.com' function prodApiOrigin(): string | null { + // 开发走 Vite 代理,不改写为跨域绝对地址 + if (import.meta.env.DEV) return null const override = (import.meta.env.VITE_API_ORIGIN as string | undefined)?.trim() if (override) return override.replace(/\/$/, '') - if (import.meta.env.DEV) return null return DEFAULT_PROD_API } @@ -76,11 +77,28 @@ export function rewriteBrowserApiPath(url: string): string { } if (path.startsWith('/Track')) { + // ideship:/Track/Track/Order → /track/Track/Order + // nanafa:保持 /track + /Track/Track/Order + const useSingle = + String(import.meta.env.VITE_DEPLOY_TARGET || '').toLowerCase() === 'ideship' || + /ideship\.com/i.test(origin) + if (useSingle && path.startsWith('/Track/Track/')) { + return `${origin}/track/Track/${path.slice('/Track/Track/'.length)}` + } return `${origin}/track${path}` } if (path.startsWith('/trackApi/')) { - return `${origin}/track/${path.slice('/trackApi/'.length)}` + const rest = path.slice('/trackApi/'.length) + const useSingle = + String(import.meta.env.VITE_DEPLOY_TARGET || '').toLowerCase() === 'ideship' || + /ideship\.com/i.test(origin) + // trackApi/Track/Order → /track/Track/Order + if (useSingle && rest.startsWith('Track/')) { + return `${origin}/track/${rest}` + } + // nanafa 历史:trackApi/Track/Order → /track/Track/Track/Order(与双 Track 客户端一致时由调用方决定) + return `${origin}/track/${rest}` } return path diff --git a/vite.config.ts b/vite.config.ts index 99c1cfa..db17795 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,10 +14,33 @@ import configCompressPlugin from './config/plugin/compress'; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); - // Admin API 目标:由 VITE_OMS_ADMIN_URL 决定(开发默认线上) + // Admin API 目标:由 VITE_OMS_ADMIN_URL 决定(开发走代理,避免浏览器 CORS) const omsAdminTarget = ( - env.VITE_OMS_ADMIN_URL || 'http://api.nanafa.com/admin' + env.VITE_OMS_ADMIN_URL || env.VITE_API_ADMIN_URL || 'http://api.nanafa.com/admin' ).replace(/\/$/, ''); + // API 根(itfx/track):优先 VITE_API_ORIGIN,否则从 Admin URL 去掉 /admin + const apiOrigin = ( + env.VITE_API_ORIGIN || + omsAdminTarget.replace(/\/admin\/?$/, '') || + 'http://api.nanafa.com' + ).replace(/\/$/, ''); + // ideship:PATHBASE=/track → /track/Track/Order/... + // nanafa:网关仍吃 /track/Track/Track/Order/...(前端历史双 Track) + const trackUseSingleSegment = + String(env.VITE_DEPLOY_TARGET || '').toLowerCase() === 'ideship' || + /ideship\.com/i.test(apiOrigin); + + const rewriteTrackProxyPath = (path: string) => { + if (trackUseSingleSegment) { + if (path.startsWith('/Track/Track/')) { + return `/track/Track/${path.slice('/Track/Track/'.length)}`; + } + if (path.startsWith('/Track/') || path === '/Track') { + return `/track${path}`; + } + } + return `/track${path}`; + }; return { server: { @@ -34,16 +57,17 @@ export default defineConfig(({ mode }) => { changeOrigin: true, secure: false, }, - // 上传静态资源:/api/upload/xxx -> http://api.nanafa.com/upload/xxx + // 上传静态资源:/api/upload/xxx -> {apiOrigin}/upload/xxx(Admin 多为 /admin/uploads) // 必须放在通用 /api 规则前,避免被转发到 /itfx/upload 导致 404 '/api/upload': { - target: 'http://api.nanafa.com', + target: apiOrigin, changeOrigin: true, + secure: false, rewrite: (path) => path.replace(/^\/api/, ''), timeout: 30000, proxyTimeout: 30000, }, - // Admin API:目标由 VITE_OMS_ADMIN_URL 决定(默认 http://api.nanafa.com/admin) + // Admin API:目标由 VITE_OMS_ADMIN_URL 决定 '/rbac': { target: omsAdminTarget, changeOrigin: true, @@ -281,22 +305,24 @@ export default defineConfig(({ mode }) => { secure: false, rewrite: (path) => path.replace(/^\/api/, ''), }, - // 轨迹(track)43.139.210.35:8889 -> http://api.nanafa.com/track,路径与 rbac、api 一致:/Track/xxx + // 轨迹(track):{apiOrigin}/track/... '/Track': { - target: 'http://api.nanafa.com', + target: apiOrigin, changeOrigin: true, - rewrite: (path) => '/track' + path, + secure: false, + rewrite: rewriteTrackProxyPath, configure: (proxy) => { proxy.on('error', (err, req, res) => { console.error('proxy error', err); }); }, }, - // API(itfx)43.139.210.35:8888 -> http://api.nanafa.com/itfx + // API(itfx):{apiOrigin}/itfx // 使用正则表达式匹配,排除前端路由路径 '^/api/(?!upstreamInterface|upstreamInterfaceConfig|upstreamInterfaceConfigEdit|downstreamInterface|downstreamInterface/newPort|appList|appList/createApplication|requestLog|callStatistics|apiDebugger|trackApi)': { - target: 'http://api.nanafa.com/itfx', + target: `${apiOrigin}/itfx`, changeOrigin: true, + secure: false, rewrite: (path) => path.replace(/^\/api/, ''), timeout: 30000, proxyTimeout: 30000,