产品化改造:完善本地集成与启动体验
This commit is contained in:
@@ -486,13 +486,15 @@ function App() {
|
||||
|
||||
const deps = result?.results ?? [];
|
||||
const hasMissingOrError = deps.some(
|
||||
(d: { status: string }) =>
|
||||
d.status === "missing" || d.status === "error",
|
||||
(d: { status: string; required?: boolean }) =>
|
||||
d.required !== false &&
|
||||
(d.status === "missing" || d.status === "error"),
|
||||
);
|
||||
const missingDeps = deps
|
||||
.filter(
|
||||
(d: { status: string }) =>
|
||||
d.status === "missing" || d.status === "error",
|
||||
(d: { status: string; required?: boolean }) =>
|
||||
d.required !== false &&
|
||||
(d.status === "missing" || d.status === "error"),
|
||||
)
|
||||
.map((d: { name: string; status: string }) => d.name);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
syncCookieAndGetNewSessionUrl,
|
||||
syncCookieAndGetChatUrl,
|
||||
persistTicketCookie,
|
||||
normalizeLocalBackendRedirect,
|
||||
} from "../../services/utils/sessionUrl";
|
||||
import { logger } from "../../services/utils/logService";
|
||||
import { APP_DISPLAY_NAME } from "@shared/constants";
|
||||
@@ -89,19 +90,47 @@ function SessionsPage({
|
||||
}
|
||||
};
|
||||
const onWillRedirect = (e: any) => {
|
||||
const normalizedUrl = normalizeLocalBackendRedirect(
|
||||
e.newURL,
|
||||
webviewUrl,
|
||||
);
|
||||
if (normalizedUrl) {
|
||||
logger.warn(
|
||||
"[SessionsPage][WebviewNav] normalized local backend redirect",
|
||||
"SessionsPage",
|
||||
{
|
||||
from: e.oldURL,
|
||||
to: e.newURL,
|
||||
normalizedUrl,
|
||||
},
|
||||
);
|
||||
e.preventDefault?.();
|
||||
el.loadURL?.(normalizedUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("[SessionsPage][WebviewNav] will-redirect", "SessionsPage", {
|
||||
from: e.oldURL,
|
||||
to: e.newURL,
|
||||
});
|
||||
};
|
||||
const onDidFailLoad = (e: any) => {
|
||||
logger.warn("[SessionsPage][WebviewNav] did-fail-load", "SessionsPage", {
|
||||
url: e.validatedURL || e.url,
|
||||
errorCode: e.errorCode,
|
||||
errorDescription: e.errorDescription,
|
||||
});
|
||||
};
|
||||
|
||||
el.addEventListener("did-navigate", onDidNavigate);
|
||||
el.addEventListener("did-navigate-in-page", onDidNavigate);
|
||||
el.addEventListener("will-redirect", onWillRedirect);
|
||||
el.addEventListener("did-fail-load", onDidFailLoad);
|
||||
return () => {
|
||||
el.removeEventListener("did-navigate", onDidNavigate);
|
||||
el.removeEventListener("did-navigate-in-page", onDidNavigate);
|
||||
el.removeEventListener("will-redirect", onWillRedirect);
|
||||
el.removeEventListener("did-fail-load", onDidFailLoad);
|
||||
};
|
||||
}, [view, webviewUrl]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
buildRedirectUrl,
|
||||
buildNewSessionUrl,
|
||||
buildChatSessionUrl,
|
||||
normalizeLocalBackendRedirect,
|
||||
syncSessionCookie,
|
||||
syncCookieAndGetRedirectUrl,
|
||||
syncCookieAndGetNewSessionUrl,
|
||||
@@ -87,6 +88,51 @@ describe("buildChatSessionUrl", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeLocalBackendRedirect", () => {
|
||||
it("normalizes local redirects that lost protocol and port", () => {
|
||||
expect(
|
||||
normalizeLocalBackendRedirect(
|
||||
"https://localhost/home/chat/5/26?hideMenu=true",
|
||||
"http://localhost:18081/api/sandbox/config/redirect/6?hideMenu=true",
|
||||
),
|
||||
).toBe("http://localhost:18081/home/chat/5/26?hideMenu=true");
|
||||
});
|
||||
|
||||
it("normalizes localhost and 127.0.0.1 mismatches to the configured backend", () => {
|
||||
expect(
|
||||
normalizeLocalBackendRedirect(
|
||||
"https://localhost/home/chat/5/26?hideMenu=true",
|
||||
"http://127.0.0.1:18081/api/sandbox/config/redirect/6?hideMenu=true",
|
||||
),
|
||||
).toBe("http://127.0.0.1:18081/home/chat/5/26?hideMenu=true");
|
||||
});
|
||||
|
||||
it("does not rewrite already-correct local redirects", () => {
|
||||
expect(
|
||||
normalizeLocalBackendRedirect(
|
||||
"http://localhost:18081/home/chat/5/26?hideMenu=true",
|
||||
"http://localhost:18081/api/sandbox/config/redirect/6?hideMenu=true",
|
||||
),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("does not rewrite remote domains", () => {
|
||||
expect(
|
||||
normalizeLocalBackendRedirect(
|
||||
"https://example.com/home/chat/5/26?hideMenu=true",
|
||||
"https://example.com/api/sandbox/config/redirect/6?hideMenu=true",
|
||||
),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for invalid URLs", () => {
|
||||
expect(normalizeLocalBackendRedirect("not-url", "http://localhost:18081"))
|
||||
.toBeNull();
|
||||
expect(normalizeLocalBackendRedirect("https://localhost", "not-url"))
|
||||
.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("syncSessionCookie", () => {
|
||||
it("不设 domain 和 secure,由主进程根据 URL scheme 判断", async () => {
|
||||
await syncSessionCookie("https://app.example.com:8080/path", "tok123");
|
||||
|
||||
@@ -66,6 +66,46 @@ export function buildChatSessionUrl(domain: string, sessionId: string): string {
|
||||
return `${normalizedDomain}/api/sandbox/config/redirect/chat/${sessionId}?hideMenu=true`;
|
||||
}
|
||||
|
||||
function isLocalBackendHost(hostname: string): boolean {
|
||||
return hostname === "localhost" || hostname === "127.0.0.1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Some local backend builds redirect `http://localhost:18081/...` to
|
||||
* `https://localhost/...`, losing both the protocol and port. Normalize only
|
||||
* that local-only case so embedded webviews keep using the configured backend.
|
||||
*/
|
||||
export function normalizeLocalBackendRedirect(
|
||||
redirectUrl: string,
|
||||
expectedBackendUrl: string,
|
||||
): string | null {
|
||||
try {
|
||||
const redirect = new URL(redirectUrl);
|
||||
const expected = new URL(expectedBackendUrl);
|
||||
|
||||
if (
|
||||
!isLocalBackendHost(expected.hostname) ||
|
||||
!isLocalBackendHost(redirect.hostname)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
redirect.protocol === expected.protocol &&
|
||||
redirect.port === expected.port
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
redirect.protocol = expected.protocol;
|
||||
redirect.host = expected.host;
|
||||
const normalized = redirect.toString();
|
||||
return normalized === redirectUrl ? null : normalized;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncSessionCookie(
|
||||
domain: string,
|
||||
token: string,
|
||||
|
||||
Reference in New Issue
Block a user