// utils.ts // 带重试机制的 fetch 封装 const fetchWithRetry = async (url: string, options: RequestInit, maxRetries = 3, delay = 1000): Promise => { let lastError: Error; for (let i = 0; i <= maxRetries; i++) { try { const response = await fetch(url, options); if (response.status === 429) { if (i < maxRetries) { const retryDelay = delay * Math.pow(2, i) + Math.random() * 1000; // 指数退避+随机抖动 await new Promise(resolve => setTimeout(resolve, retryDelay)); continue; } else { throw new Error(`Too Many Requests (429). Max retries exceeded.`); } } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response; } catch (error) { lastError = error as Error; if (i < maxRetries) { const retryDelay = delay * Math.pow(2, i) + Math.random() * 1000; await new Promise(resolve => setTimeout(resolve, retryDelay)); } } } throw lastError!; }; export const urlToBlob = async (url: string): Promise => { try { const response = await fetchWithRetry(url, { headers: { "accept": 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8' } }, 3, 2000); // 最多重试3次,基础延迟2秒 return await response.blob(); } catch (error) { console.error(`获取图片失败 (${url}):`, error); throw error; } }; export const urlToFile = async (url: string, fileName: string): Promise => { try { const blob = await urlToBlob(url); return new File([blob], fileName, { type: blob.type, lastModified: new Date().getTime() }); } catch (error) { console.error(`图片转文件失败 (${url}):`, error); return null; } }; // export const urlToBlob = async (url: string): Promise => { // return new Promise(async (resolve, reject) => { // const response = await fetch(url, { // headers: { // "accept": 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8' // } // }); // if (!response.ok) { // reject(null) // }; // resolve(await response.blob() as Blob); // 显式断言为 Blob 类型 // return // const xhr = new XMLHttpRequest(); // xhr.open("GET", url, true); // xhr.responseType = "blob"; // xhr.onload = function () { // if (this.status === 200) { // resolve(this.response as Blob); // 显式断言为 Blob 类型 // } else { // reject(new Error("Error loading image")); // } // }; // xhr.onerror = function () { // reject(new Error("Network error")); // }; // xhr.send(); // }); // }; // export const urlToFile = async (url: string, fileName: string) => { // console.log("urlToFile") // return urlToBlob(url).then(blob => { // if (!blob) return null; // return new File([blob], fileName, { // type: blob.type, // lastModified: new Date().getTime() // }); // }).catch(error => { // return null; // }) // }