From 59efdb1f781ca2d47c9700e42823ab034ce6fbe7 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 2 Feb 2026 01:14:19 -0800 Subject: [PATCH] =?UTF-8?q?fix(mining-admin-web):=20=E4=BF=AE=E5=A4=8D=20A?= =?UTF-8?q?PI=20=E8=AF=B7=E6=B1=82=E8=B6=85=E6=97=B6=E5=92=8C=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - mining-admin-web 容器与后端服务在不同 Docker 网络, 无法通过公网 IP 回连 (hairpin NAT 失败) - next.config.js 生产模式强制走 mapi.szaiai.com Kong 网关, 容器内无法访问 - client.ts 使用 NEXT_PUBLIC_API_URL 导致外部 URL 被 build 时内联到客户端包 - mining-service controller 有 mining/ 前缀, 直连模式 rewrite 丢失该前缀 修复: - next.config.js: 改用 API_GATEWAY_URL 判断路由模式, 未设置则直连后端服务 - next.config.js: mining rewrite 保留 mining/ 前缀匹配 controller 路由 - client.ts: baseURL 固定为 /api, 所有请求统一走 Next.js rewrite 代理 - docker-compose.2.0.yml: 添加 TRADING_SERVICE_URL 和 MINING_SERVICE_URL 环境变量 Co-Authored-By: Claude Opus 4.5 --- backend/services/docker-compose.2.0.yml | 4 ++++ frontend/mining-admin-web/next.config.js | 23 ++++++++----------- .../mining-admin-web/src/lib/api/client.ts | 5 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/services/docker-compose.2.0.yml b/backend/services/docker-compose.2.0.yml index 4b8c6c8d..814f2d0a 100644 --- a/backend/services/docker-compose.2.0.yml +++ b/backend/services/docker-compose.2.0.yml @@ -480,6 +480,10 @@ services: PORT: 3100 NEXT_PUBLIC_API_URL: http://mining-admin-service:3023 NEXT_PUBLIC_APP_NAME: 挖矿管理后台 + # 直连后端服务 (同一 Docker 网络内, 不经 Kong 网关) + # 如需走 Kong 网关, 设置 API_GATEWAY_URL 即可 (如 https://mapi.szaiai.com) + TRADING_SERVICE_URL: http://trading-service:3022 + MINING_SERVICE_URL: http://mining-service:3021 ports: - "3100:3100" healthcheck: diff --git a/frontend/mining-admin-web/next.config.js b/frontend/mining-admin-web/next.config.js index 696a9ded..48c051bd 100644 --- a/frontend/mining-admin-web/next.config.js +++ b/frontend/mining-admin-web/next.config.js @@ -3,27 +3,21 @@ const nextConfig = { reactStrictMode: true, output: 'standalone', async rewrites() { - // 获取 API 基础 URL(Kong 网关地址) - // 生产环境: https://mapi.szaiai.com - // 开发环境: http://localhost:3023 (mining-admin-service) - const apiGatewayUrl = process.env.API_GATEWAY_URL || 'https://mapi.szaiai.com'; + // API 路由模式: + // 1. 设置了 API_GATEWAY_URL -> 通过 Kong 网关代理 (适用于前端与后端不在同一 Docker 网络) + // 2. 未设置 API_GATEWAY_URL -> 直连各后端服务 (适用于同一 Docker 网络, 推荐 standalone 模式) + const apiGatewayUrl = process.env.API_GATEWAY_URL || ''; const miningAdminUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3023'; const tradingServiceUrl = process.env.TRADING_SERVICE_URL || 'http://localhost:3022'; const miningServiceUrl = process.env.MINING_SERVICE_URL || 'http://localhost:3021'; - // 检查是否是生产环境(使用 Kong 网关) - const isProduction = process.env.NODE_ENV === 'production'; - // 移除末尾可能存在的路径避免重复 const cleanMiningAdminUrl = miningAdminUrl.replace(/\/api\/v2.*$/, ''); const cleanTradingUrl = tradingServiceUrl.replace(/\/api\/v2.*$/, ''); const cleanMiningUrl = miningServiceUrl.replace(/\/api\/v2.*$/, ''); - if (isProduction) { - // 生产环境:通过 Kong 网关 - // /api/trading/* -> Kong -> trading-service - // /api/mining/* -> Kong -> mining-service - // /api/* -> Kong -> mining-admin-service + if (apiGatewayUrl) { + // 通过 Kong 网关: 所有请求经 Kong 路由分发到各服务 return [ { source: '/api/trading/:path*', @@ -39,15 +33,16 @@ const nextConfig = { }, ]; } else { - // 开发环境:直连各服务 + // 直连各服务: 前端与后端在同一 Docker 网络内直接通信 return [ { source: '/api/trading/:path*', destination: `${cleanTradingUrl}/api/v2/:path*`, }, { + // mining-service 的 controller 有 mining/ 前缀, 需保留 source: '/api/mining/:path*', - destination: `${cleanMiningUrl}/api/v2/:path*`, + destination: `${cleanMiningUrl}/api/v2/mining/:path*`, }, { source: '/api/:path*', diff --git a/frontend/mining-admin-web/src/lib/api/client.ts b/frontend/mining-admin-web/src/lib/api/client.ts index a391617c..93018b34 100644 --- a/frontend/mining-admin-web/src/lib/api/client.ts +++ b/frontend/mining-admin-web/src/lib/api/client.ts @@ -1,7 +1,8 @@ import axios from 'axios'; -// 生产环境使用 NEXT_PUBLIC_API_URL,开发环境使用 /api 代理 -const baseURL = process.env.NEXT_PUBLIC_API_URL || '/api'; +// 始终使用 /api 前缀, 通过 Next.js rewrite 代理到后端服务 +// NEXT_PUBLIC_API_URL 仅供服务端使用 (next.config.js rewrites), 不在客户端使用 +const baseURL = '/api'; export const apiClient = axios.create({ baseURL,