From c96bb5fa2d8d7c5f6fe2815c5d56afb5554d31f2 Mon Sep 17 00:00:00 2001 From: chengkml <45121067+chengkml@users.noreply.github.com> Date: Sat, 16 May 2026 16:56:18 +0800 Subject: [PATCH] fix: proxy prod api traffic through web entry --- MEMORY.md | 1 + deploy/pro-deploy/compose.yml | 11 ++++++++++ deploy/pro-deploy/nginx.conf | 41 +++++++++++++++++++++++++++++++++++ memory/2026-05-16.md | 25 +++++++++++++++++++++ web/src/lib/api.ts | 6 +---- 5 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 deploy/pro-deploy/nginx.conf diff --git a/MEMORY.md b/MEMORY.md index 86545bd..26295a8 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -73,6 +73,7 @@ - 认证请求与 WebSocket 连接均统一复用该运行时 API 基址解析逻辑。 - `NEXT_PUBLIC_API_BASE_URL` 必须只配置“协议 + 主机 + 可选端口”,不要额外带 `/api` 前缀;当前前端请求路径已自行拼接 `/api/v1/...`,若环境变量写成 `https://host/api` 会落成 `/api/api/v1/...`。 - 通过 IP:3000 直接访问站点时,后端 `API_CORS_ORIGINS` 必须显式包含该页面 origin(例如 `http://223.109.142.84:3000`);仅放行正式域名会导致浏览器在登录预检阶段返回 `Disallowed CORS origin`。 +- 生产若通过公网 `IP:3000` 暴露前端,而公网 `8000` 不可直达,则应由入口反代统一承接:浏览器端对 loopback API 基址一律回落到当前站点 origin,`/api/*` 与 `/api/v1/ws` 通过部署层反代到 `api:8000`,避免浏览器直接访问 `host:8000`。 ## 前端构建稳定性口径(2026-04-13) diff --git a/deploy/pro-deploy/compose.yml b/deploy/pro-deploy/compose.yml index e1d19fb..db61e13 100644 --- a/deploy/pro-deploy/compose.yml +++ b/deploy/pro-deploy/compose.yml @@ -162,6 +162,17 @@ services: NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL} NEXT_PUBLIC_APP_BASE_PATH: ${NEXT_PUBLIC_APP_BASE_PATH:-/fl} NODE_ENV: production + expose: + - "3000" + restart: unless-stopped + + proxy: + image: docker.m.daocloud.io/library/nginx:1.27-alpine + depends_on: + - web + - api ports: - "3000:3000" + volumes: + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro restart: unless-stopped diff --git a/deploy/pro-deploy/nginx.conf b/deploy/pro-deploy/nginx.conf new file mode 100644 index 0000000..c64c545 --- /dev/null +++ b/deploy/pro-deploy/nginx.conf @@ -0,0 +1,41 @@ +server { + listen 3000; + server_name _; + + client_max_body_size 200m; + + location /api/v1/ws { + proxy_pass http://api:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } + + location /api/ { + proxy_pass http://api:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } + + location / { + proxy_pass http://web:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } +} diff --git a/memory/2026-05-16.md b/memory/2026-05-16.md index 8ce5781..641efd8 100644 --- a/memory/2026-05-16.md +++ b/memory/2026-05-16.md @@ -47,3 +47,28 @@ - 风险与关注点: - 在线 `api` 仍配置 `REFRESH_COOKIE_SECURE=true`;若继续通过纯 HTTP IP 访问,刷新 token cookie 可能不会被浏览器持久化。短期内不影响本次“登录预检被拦截”的修复,但后续若要稳定保留登录态,建议切到 HTTPS 域名访问,或在明确接受风险的前提下改为 `false`。 + +## Work Log - 认证刷新超时改为同源反代(2026-05-16) + +- 背景: + - 浏览器请求 `POST http://223.109.142.84:8000/api/v1/auth/refresh` 超时,控制台报 `Failed to fetch`。 + - 容器内访问 `http://223.109.142.84:3000/fl` 正常返回 `200`,但访问 `http://223.109.142.84:8000/health` 仍超时;同时 `http://127.0.0.1:8000/health` 在 `api` 容器内正常返回 `200`。 + - 说明故障不在 `auth/refresh` 业务逻辑,而在“浏览器直连公网 `:8000`”这条访问链路。 + +- 本次改动: + - `web/src/lib/api.ts` + - 浏览器端在发现构建注入的 API 基址仍为 loopback 且当前页面不在 loopback 主机时,不再改写到 `当前主机:8000`,而是直接回落到 `window.location.origin`。 + - `deploy/pro-deploy/compose.yml` + - 生产部署新增 `proxy`(nginx)服务,占用宿主机 `3000`。 + - `web` 改为仅在 Compose 内网暴露 `3000`,不再直接占用宿主机端口。 + - `deploy/pro-deploy/nginx.conf` + - `/api/*` 反代到 `api:8000`。 + - `/api/v1/ws` 使用 Upgrade 头反代到 `api:8000`。 + - 其余页面流量反代到 `web:3000`。 + +- 验证: + - 本地 `nft list ruleset` 显示 Docker 已为宿主机 `3000/8000` 建立映射,但容器内访问公网 `:8000` 超时、访问公网 `:3000` 正常,支持“对外入口应统一走 `3000` 反代”的判断。 + - 待同步部署目录并重建 `web/proxy` 容器后,再做浏览器与 `curl` 复测。 + +- 风险与关注点: + - 当前在线 `REFRESH_COOKIE_SECURE=true`;若继续通过纯 HTTP IP 访问,浏览器可能仍不会持久化 refresh cookie。若部署后出现“登录后刷新即掉线”,需将当前环境的 `REFRESH_COOKIE_SECURE` 调整为 `false` 或切到 HTTPS 入口。 diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 5cb66ee..edff085 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -31,11 +31,7 @@ export function getApiBaseUrl(): string { return trimTrailingSlash(configured); } - parsed.hostname = browserHost; - if (!parsed.port) { - parsed.port = "8000"; - } - return trimTrailingSlash(parsed.toString()); + return trimTrailingSlash(window.location.origin); } export const API_BASE_URL = getApiBaseUrl();