ALIEZ 1 månad sedan
förälder
incheckning
86542bd700
3 ändrade filer med 28 tillägg och 12 borttagningar
  1. 4 5
      ecosystem.config.cjs
  2. 2 2
      server.js
  3. 22 5
      src/lib/env.ts

+ 4 - 5
ecosystem.config.cjs

@@ -2,10 +2,9 @@ const path = require("path");
 
 /**
  * PM2 多环境说明:
- * - jchl-test:测试环境(默认端口 3100)
- * - jchl-prod:生产环境(默认端口 3000)
+ * - jchl-test / jchl-prod:默认监听 `PORT=3000`(与 `server.js` 一致);需沿用 :4000 时在 PM2 或系统环境中显式设置 `PORT`。
  *
- * 端口可在下面 env 中改,或由服务器上的 .env.production / 系统环境变量覆盖。
+ * 端口可在下面 env 中改(默认 3000),或由服务器上的 .env.production / 系统环境变量覆盖。
  * 敏感信息不要写进本文件,用 PM2 --env 或服务器环境变量注入。
  *
  * NEXT_PUBLIC_*(如 API 地址)在 next build 时已打入前端包;PM2 里再改不会更新浏览器里的接口域名。
@@ -32,7 +31,7 @@ module.exports = {
       max_memory_restart: "800M",
       env: {
         NODE_ENV: "production",
-        PORT: 4000,
+        PORT: 3000,
       },
     },
     {
@@ -47,7 +46,7 @@ module.exports = {
       max_memory_restart: "1G",
       env: {
         NODE_ENV: "production",
-        PORT: 4000,
+        PORT: 3000,
       },
     },
   ],

+ 2 - 2
server.js

@@ -3,11 +3,11 @@ const { createServer } = require('http');
 const { parse } = require('url');
 const next = require('next');
 
-const port = Number(process.env.PORT || 4000);
+const port = Number(process.env.PORT || 3000);
 
 /**
  * 自定义 server 若写 `next({ dev: false })` 不传 port,Next 内部仍默认 3000(见 next/dist/server/next.js),
- * 与 `listen(4000)` 不一致时,307 Location 会变成 `http://jinclab.com:3000/zh` 这类错误地址
+ * 与 `listen(...)` 不一致时,307 Location 会变成错误端口。此处默认 3000,与 Next 一致;生产若反代到其它端口请设 `PORT`
  *
  * 反代终止 TLS 后须传 `X-Forwarded-Proto: https`;若漏传,协议会判成 http。
  * 若 Host 误带内网端口,与 NEXT_PUBLIC_SITE_URL 对齐时去掉端口。

+ 22 - 5
src/lib/env.ts

@@ -47,6 +47,17 @@ function resolveApiBaseUrlValue(raw: string | undefined): string {
   return s;
 }
 
+/** PM2 / server.js 常用对外误显端口;登录跳转一律不写进地址栏(本机回环除外)。 */
+const DEFAULT_NODE_PUBLIC_PORT = "4000";
+
+function isLoopbackHostname(hostname: string): boolean {
+  return (
+    hostname === "localhost" ||
+    hostname === "127.0.0.1" ||
+    hostname === "[::1]"
+  );
+}
+
 /** 本地 / 局域网访问时保留当前 origin(含端口),避免误跳到 :80/:443 上无服务。 */
 function shouldPreserveCurrentOriginPort(hostname: string): boolean {
   if (
@@ -74,17 +85,23 @@ function shouldPreserveCurrentOriginPort(hostname: string): boolean {
 
 /**
  * 登录页跳转地址(仅浏览器)。
- * - `window.location.assign("/auth/login")` 会保留 `:4000` 等当前端口
+ * - 当前端口为 **4000** 且非本机回环时,强制用「协议 + 主机名(无端口)」拼 `/auth/login`,去掉地址栏里的 `:4000`
  * - 若已配置 `NEXT_PUBLIC_SITE_URL` 且当前 host 与站点一致,优先用该 canonical origin。
- * - 否则对公网域名用「当前协议 + 主机名(不含端口)」拼路径,这样即使构建时未打入
- *   SITE_URL,从 `jinclab.com:4000` 也会跳到 `https://jinclab.com/auth/login`(由中间件补 `/zh`)。
- * - localhost / 局域网 IP 仍用相对路径,保留端口。
+ * - localhost / 局域网 IP 且非上述 4000 规则:仍用相对路径,保留端口。
  */
 export function resolveAuthLoginHref(): string {
   const path = "/auth/login";
   if (typeof window === "undefined") return path;
 
-  const { protocol, hostname } = window.location;
+  const { protocol, hostname, port } = window.location;
+
+  if (port === DEFAULT_NODE_PUBLIC_PORT && !isLoopbackHostname(hostname)) {
+    try {
+      return new URL(path, `${protocol}//${hostname}/`).href;
+    } catch {
+      /* fall through */
+    }
+  }
 
   const site = process.env.NEXT_PUBLIC_SITE_URL?.trim().replace(/\/$/, "");
   if (site) {