ALIEZ 1 ay önce
ebeveyn
işleme
bcdd456c74
1 değiştirilmiş dosya ile 51 ekleme ve 17 silme
  1. 51 17
      src/lib/env.ts

+ 51 - 17
src/lib/env.ts

@@ -47,39 +47,73 @@ function resolveApiBaseUrlValue(raw: string | undefined): string {
   return s;
 }
 
+/** 本地 / 局域网访问时保留当前 origin(含端口),避免误跳到 :80/:443 上无服务。 */
+function shouldPreserveCurrentOriginPort(hostname: string): boolean {
+  if (
+    hostname === "localhost" ||
+    hostname === "127.0.0.1" ||
+    hostname === "[::1]"
+  ) {
+    return true;
+  }
+  const parts = hostname.split(".");
+  if (
+    parts.length === 4 &&
+    parts.every((p) => /^\d+$/.test(p)) &&
+    parts[0] !== undefined &&
+    parts[1] !== undefined
+  ) {
+    const a = Number(parts[0]);
+    const b = Number(parts[1]);
+    if (a === 10) return true;
+    if (a === 172 && b >= 16 && b <= 31) return true;
+    if (a === 192 && b === 168) return true;
+  }
+  return false;
+}
+
 /**
  * 登录页跳转地址(仅浏览器)。
- * 相对路径 `/auth/login` 会保留当前 URL 的端口;若用户通过 `jinclab.com:4000` 访问而
- * `NEXT_PUBLIC_SITE_URL` 为无端口的公网地址,则用后者 origin,避免地址栏出现 `:4000`。
- * 本地开发未配置 SITE_URL 时仍用相对路径。
+ * - `window.location.assign("/auth/login")` 会保留 `:4000` 等当前端口。
+ * - 若已配置 `NEXT_PUBLIC_SITE_URL` 且当前 host 与站点一致,优先用该 canonical origin。
+ * - 否则对公网域名用「当前协议 + 主机名(不含端口)」拼路径,这样即使构建时未打入
+ *   SITE_URL,从 `jinclab.com:4000` 也会跳到 `https://jinclab.com/auth/login`(由中间件补 `/zh`)。
+ * - localhost / 局域网 IP 仍用相对路径,保留端口。
  */
 export function resolveAuthLoginHref(): string {
   const path = "/auth/login";
   if (typeof window === "undefined") return path;
 
+  const { protocol, hostname } = window.location;
+
   const site = process.env.NEXT_PUBLIC_SITE_URL?.trim().replace(/\/$/, "");
-  if (!site) return path;
+  if (site) {
+    try {
+      const siteUrl = new URL(site);
+      const canonical = siteUrl.hostname;
+      const allowedHosts = new Set([canonical, `www.${canonical}`]);
+      try {
+        const current = new URL(window.location.href);
+        if (allowedHosts.has(current.hostname)) {
+          return `${siteUrl.origin}${path}`;
+        }
+      } catch {
+        /* fall through */
+      }
+    } catch {
+      /* invalid NEXT_PUBLIC_SITE_URL */
+    }
+  }
 
-  let siteUrl: URL;
-  try {
-    siteUrl = new URL(site);
-  } catch {
+  if (shouldPreserveCurrentOriginPort(hostname)) {
     return path;
   }
 
-  const canonical = siteUrl.hostname;
-  const allowedHosts = new Set([canonical, `www.${canonical}`]);
-
   try {
-    const current = new URL(window.location.href);
-    if (allowedHosts.has(current.hostname)) {
-      return `${siteUrl.origin}${path}`;
-    }
+    return new URL(path, `${protocol}//${hostname}/`).href;
   } catch {
     return path;
   }
-
-  return path;
 }
 
 export function resolveAppEnv(): AppEnv {