fix(web): stabilize homepage live status
This commit is contained in:
@@ -50,6 +50,36 @@ interface UseCSRFReturn {
|
||||
refresh: () => Promise<void>;
|
||||
}
|
||||
|
||||
let cachedCSRFToken: string | null = null;
|
||||
let csrfInFlight: Promise<string> | null = null;
|
||||
|
||||
async function requestCSRFToken(force = false): Promise<string> {
|
||||
if (cachedCSRFToken && !force) return cachedCSRFToken;
|
||||
if (csrfInFlight) return csrfInFlight;
|
||||
|
||||
csrfInFlight = (async () => {
|
||||
const apiUrl = getApiUrl();
|
||||
const response = await fetch(`${apiUrl}/api/v1/csrf/token`, {
|
||||
method: "GET",
|
||||
credentials: "include", // 確保 cookie 被設定
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch CSRF token: ${response.status}`);
|
||||
}
|
||||
|
||||
const data: CSRFTokenResponse = await response.json();
|
||||
cachedCSRFToken = data.token;
|
||||
return data.token;
|
||||
})();
|
||||
|
||||
try {
|
||||
return await csrfInFlight;
|
||||
} finally {
|
||||
csrfInFlight = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CSRF Token Hook
|
||||
*
|
||||
@@ -57,27 +87,24 @@ interface UseCSRFReturn {
|
||||
* 供敏感請求使用。
|
||||
*/
|
||||
export function useCSRF(): UseCSRFReturn {
|
||||
const [csrfToken, setCSRFToken] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [csrfToken, setCSRFToken] = useState<string | null>(cachedCSRFToken);
|
||||
const [isLoading, setIsLoading] = useState(!cachedCSRFToken);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
const fetchToken = useCallback(async () => {
|
||||
const fetchToken = useCallback(async (force = false) => {
|
||||
if (cachedCSRFToken && !force) {
|
||||
setCSRFToken(cachedCSRFToken);
|
||||
setIsLoading(false);
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const apiUrl = getApiUrl();
|
||||
const response = await fetch(`${apiUrl}/api/v1/csrf/token`, {
|
||||
method: "GET",
|
||||
credentials: "include", // 確保 cookie 被設定
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch CSRF token: ${response.status}`);
|
||||
}
|
||||
|
||||
const data: CSRFTokenResponse = await response.json();
|
||||
setCSRFToken(data.token);
|
||||
const token = await requestCSRFToken(force);
|
||||
setCSRFToken(token);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error(String(err)));
|
||||
console.error("[useCSRF] Failed to fetch CSRF token:", err);
|
||||
@@ -107,7 +134,7 @@ export function useCSRF(): UseCSRFReturn {
|
||||
isLoading,
|
||||
error,
|
||||
getHeaders,
|
||||
refresh: fetchToken,
|
||||
refresh: () => fetchToken(true),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user