84 lines
2.6 KiB
JavaScript
84 lines
2.6 KiB
JavaScript
// frontend/js/services/api.js
|
|
var APIClientError = class extends Error {
|
|
constructor(message, status, code, rawMessageFromServer) {
|
|
super(message);
|
|
this.name = "APIClientError";
|
|
this.status = status;
|
|
this.code = code;
|
|
this.rawMessageFromServer = rawMessageFromServer;
|
|
}
|
|
};
|
|
var apiPromiseCache = /* @__PURE__ */ new Map();
|
|
async function apiFetch(url, options = {}) {
|
|
const isGetRequest = !options.method || options.method.toUpperCase() === "GET";
|
|
const cacheKey = isGetRequest && !options.noCache ? url : null;
|
|
if (cacheKey && apiPromiseCache.has(cacheKey)) {
|
|
return apiPromiseCache.get(cacheKey);
|
|
}
|
|
const token = localStorage.getItem("bearerToken");
|
|
const headers = {
|
|
"Content-Type": "application/json",
|
|
...options.headers
|
|
};
|
|
if (token) {
|
|
headers["Authorization"] = `Bearer ${token}`;
|
|
}
|
|
const requestPromise = (async () => {
|
|
try {
|
|
const response = await fetch(url, { ...options, headers });
|
|
if (response.status === 401) {
|
|
if (cacheKey) apiPromiseCache.delete(cacheKey);
|
|
localStorage.removeItem("bearerToken");
|
|
if (window.location.pathname !== "/login") {
|
|
window.location.href = "/login?error=\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u3002";
|
|
}
|
|
throw new APIClientError("Unauthorized", 401, "UNAUTHORIZED", "Session expired or token is invalid.");
|
|
}
|
|
if (!response.ok) {
|
|
let errorData = null;
|
|
let rawMessage = "";
|
|
try {
|
|
rawMessage = await response.text();
|
|
if (rawMessage) {
|
|
errorData = JSON.parse(rawMessage);
|
|
}
|
|
} catch (e) {
|
|
errorData = { error: { code: "UNKNOWN_FORMAT", message: rawMessage || response.statusText } };
|
|
}
|
|
const code = errorData?.error?.code || "UNKNOWN_ERROR";
|
|
const messageFromServer = errorData?.error?.message || rawMessage || "No message provided by server.";
|
|
const error = new APIClientError(
|
|
`API request failed: ${response.status}`,
|
|
response.status,
|
|
code,
|
|
messageFromServer
|
|
);
|
|
throw error;
|
|
}
|
|
return response;
|
|
} catch (error) {
|
|
if (cacheKey) apiPromiseCache.delete(cacheKey);
|
|
throw error;
|
|
}
|
|
})();
|
|
if (cacheKey) {
|
|
apiPromiseCache.set(cacheKey, requestPromise);
|
|
}
|
|
return requestPromise;
|
|
}
|
|
async function apiFetchJson(url, options = {}) {
|
|
try {
|
|
const response = await apiFetch(url, options);
|
|
const clonedResponse = response.clone();
|
|
const jsonData = await clonedResponse.json();
|
|
return jsonData;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export {
|
|
apiFetch,
|
|
apiFetchJson
|
|
};
|