fix(dashboard): auto-prepend https:// for backend URLs without protocol

Previously, a URL like api.lightjunction.online:3000 (without https://)
was stored as-is and treated as a relative path, causing requests to
hit the frontend origin instead of the configured backend. URLs with a
single slash like https:/api... were also incorrectly normalized.

Now normalizeConfiguredApiBaseUrl always prepends https:// if the input
doesn't start with http:// or https://, and apiStore.setApiBaseUrl also
normalizes before storing to keep state and localStorage consistent.
This commit is contained in:
LIghtJUNction
2026-04-08 21:18:16 +08:00
parent 07b49b9e97
commit 3f1a14836f
3 changed files with 23 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
import { defineStore } from "pinia";
import { getApiBaseUrl, setApiBaseUrl } from "@/utils/request";
import { getApiBaseUrl, setApiBaseUrl, normalizeConfiguredApiBaseUrl } from "@/utils/request";
export type ApiPreset = {
name: string;
@@ -41,18 +41,18 @@ export const useApiStore = defineStore("api", {
* @param url 后端地址,例如 http://localhost:6185
*/
setApiBaseUrl(url: string) {
// 移除尾部斜杠,确保一致性
const cleanUrl = url ? url.replace(/\/+$/, "") : "";
// Normalize: prepend https:// if missing, strip trailing slashes
const normalized = normalizeConfiguredApiBaseUrl(url);
this.apiBaseUrl = cleanUrl;
this.apiBaseUrl = normalized;
if (cleanUrl) {
localStorage.setItem("apiBaseUrl", cleanUrl);
if (normalized) {
localStorage.setItem("apiBaseUrl", normalized);
} else {
localStorage.removeItem("apiBaseUrl");
}
setApiBaseUrl(cleanUrl);
setApiBaseUrl(normalized);
},
/**

View File

@@ -68,7 +68,12 @@ function normalizeBaseUrl(baseUrl: string | null | undefined): string {
export function normalizeConfiguredApiBaseUrl(
baseUrl: string | null | undefined,
): string {
return normalizeBaseUrl(baseUrl);
const cleaned = normalizeBaseUrl(baseUrl);
// Prepend https:// if it doesn't already have a protocol
if (cleaned && !/^https?:\/\//i.test(cleaned)) {
return `https://${cleaned}`;
}
return cleaned;
}
export function getApiBaseUrlValidationError(
@@ -97,7 +102,7 @@ export function getApiBaseUrl(): string {
}
export function setApiBaseUrl(baseUrl: string | null | undefined): string {
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
const normalizedBaseUrl = normalizeConfiguredApiBaseUrl(baseUrl);
service.defaults.baseURL = normalizedBaseUrl;
return normalizedBaseUrl;
}

View File

@@ -16,7 +16,7 @@ const isDark = computed(
);
import { useI18n, useModuleI18n } from "@/i18n/composables";
import { useToast } from "@/utils/toast";
import { getApiBaseUrlValidationError } from "@/utils/request";
import { getApiBaseUrlValidationError, normalizeConfiguredApiBaseUrl } from "@/utils/request";
const cardVisible = ref(false);
const router = useRouter();
@@ -28,7 +28,7 @@ const { tm: t } = useModuleI18n("features/auth");
const toast = useToast();
const serverConfigDialog = ref(false);
const apiUrl = ref(apiStore.apiBaseUrl);
const apiUrl = ref(normalizeConfiguredApiBaseUrl(apiStore.apiBaseUrl));
// URL parameter handling for shareable config
function applyUrlParams() {
@@ -36,10 +36,11 @@ function applyUrlParams() {
const apiUrlParam = params.get("api_url");
const usernameParam = params.get("username");
if (apiUrlParam) {
apiUrl.value = apiUrlParam;
const validationError = getApiBaseUrlValidationError(apiUrlParam);
const normalized = normalizeConfiguredApiBaseUrl(apiUrlParam);
apiUrl.value = normalized;
const validationError = getApiBaseUrlValidationError(normalized);
if (!validationError) {
apiStore.setApiBaseUrl(apiUrlParam);
apiStore.setApiBaseUrl(normalized);
}
}
if (usernameParam) {
@@ -71,13 +72,14 @@ const newPresetName = ref("");
const newPresetUrl = ref("");
function saveApiUrl() {
const validationError = getApiBaseUrlValidationError(apiUrl.value);
const normalized = normalizeConfiguredApiBaseUrl(apiUrl.value);
const validationError = getApiBaseUrlValidationError(normalized);
if (validationError) {
toast.error(validationError);
return;
}
apiStore.setApiBaseUrl(apiUrl.value);
apiStore.setApiBaseUrl(normalized);
serverConfigDialog.value = false;
window.location.reload();
}