Explain a Backend URL/page-origin mismatch instead of a bare fetch error

A real Windows install had sync and backups fail everywhere with
"Failed to fetch" while the server itself was fully healthy - confirmed
via Invoke-WebRequest returning 200 for every endpoint the browser
couldn't reach. The page was opened via a LAN IP while Settings still
had the Backend URL set to 127.0.0.1 from an earlier session; browsers
treat those as different origins, so the server's CORS check correctly
rejected the requests, but a CORS rejection surfaces to fetch() as an
unexplained generic error with no indication of the real cause.

Settings now detects this mismatch on every render and shows the page's
actual address with a one-click button to fix it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-09-09 12:06:58 +02:00
parent c53f31bf35
commit be9a2de31a
7 changed files with 52 additions and 3 deletions

View File

@@ -70,6 +70,9 @@ export function renderSettings(deps) {
await action();
return true;
};
const pageOrigin = /^https?:$/.test(window.location.protocol) ? window.location.origin : "";
const configuredBackendUrl = String(state.settings.backendUrl || getDefaultBackendUrl()).replace(/\/+$/, "");
const backendUrlMismatch = Boolean(pageOrigin && configuredBackendUrl && pageOrigin !== configuredBackendUrl);
const ammcStatus = ammc.status || {};
const ammcOutput = Array.isArray(ammcStatus.lastOutput) ? ammcStatus.lastOutput : [];
const suggestedWsUrl = getManagedWsUrl("main");
@@ -181,6 +184,12 @@ export function renderSettings(deps) {
state.settings.backendUrl || getDefaultBackendUrl()
)}" placeholder="http://127.0.0.1:8081" />
</label>
${backendUrlMismatch ? `
<p class="settings-backend-mismatch">
${escapeHtml(t("settings.backend_url_mismatch", { origin: pageOrigin }))}
<button type="button" id="settingsUseCurrentOrigin" class="btn btn-small">${escapeHtml(t("settings.backend_url_use_current", { origin: pageOrigin }))}</button>
</p>
` : ""}
<label class="toggle decoder-reconnect-toggle">
<input type="checkbox" name="autoReconnect" ${state.settings.autoReconnect ? "checked" : ""} />
<span>${t("settings.auto_reconnect")}</span>
@@ -646,6 +655,11 @@ Erik Eriksson;654321;4WD;Associated;;</code></pre>
});
document.getElementById("settingsConnect")?.addEventListener("click", connectDecoder);
document.getElementById("settingsUseCurrentOrigin")?.addEventListener("click", () => {
state.settings.backendUrl = pageOrigin;
saveState();
renderView();
});
document.querySelectorAll('[name^="raceAudio"]').forEach((control) => {
control.addEventListener("change", persistRaceAudioFormValues);
});