utils.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // utils.ts
  2. // 带重试机制的 fetch 封装
  3. const fetchWithRetry = async (url: string, options: RequestInit, maxRetries = 3, delay = 1000): Promise<Response> => {
  4. let lastError: Error;
  5. for (let i = 0; i <= maxRetries; i++) {
  6. try {
  7. const response = await fetch(url, options);
  8. if (response.status === 429) {
  9. if (i < maxRetries) {
  10. const retryDelay = delay * Math.pow(2, i) + Math.random() * 1000; // 指数退避+随机抖动
  11. await new Promise(resolve => setTimeout(resolve, retryDelay));
  12. continue;
  13. } else {
  14. throw new Error(`Too Many Requests (429). Max retries exceeded.`);
  15. }
  16. }
  17. if (!response.ok) {
  18. throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  19. }
  20. return response;
  21. } catch (error) {
  22. lastError = error as Error;
  23. if (i < maxRetries) {
  24. const retryDelay = delay * Math.pow(2, i) + Math.random() * 1000;
  25. await new Promise(resolve => setTimeout(resolve, retryDelay));
  26. }
  27. }
  28. }
  29. throw lastError!;
  30. };
  31. export const urlToBlob = async (url: string): Promise<Blob> => {
  32. try {
  33. const response = await fetchWithRetry(url, {
  34. headers: {
  35. "accept": 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
  36. }
  37. }, 3, 2000); // 最多重试3次,基础延迟2秒
  38. return await response.blob();
  39. } catch (error) {
  40. console.error(`获取图片失败 (${url}):`, error);
  41. throw error;
  42. }
  43. };
  44. export const urlToFile = async (url: string, fileName: string): Promise<File | null> => {
  45. try {
  46. const blob = await urlToBlob(url);
  47. return new File([blob], fileName, {
  48. type: blob.type,
  49. lastModified: new Date().getTime()
  50. });
  51. } catch (error) {
  52. console.error(`图片转文件失败 (${url}):`, error);
  53. return null;
  54. }
  55. };
  56. // export const urlToBlob = async (url: string): Promise<Blob> => {
  57. // return new Promise(async (resolve, reject) => {
  58. // const response = await fetch(url, {
  59. // headers: {
  60. // "accept": 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
  61. // }
  62. // });
  63. // if (!response.ok) {
  64. // reject(null)
  65. // };
  66. // resolve(await response.blob() as Blob); // 显式断言为 Blob 类型
  67. // return
  68. // const xhr = new XMLHttpRequest();
  69. // xhr.open("GET", url, true);
  70. // xhr.responseType = "blob";
  71. // xhr.onload = function () {
  72. // if (this.status === 200) {
  73. // resolve(this.response as Blob); // 显式断言为 Blob 类型
  74. // } else {
  75. // reject(new Error("Error loading image"));
  76. // }
  77. // };
  78. // xhr.onerror = function () {
  79. // reject(new Error("Network error"));
  80. // };
  81. // xhr.send();
  82. // });
  83. // };
  84. // export const urlToFile = async (url: string, fileName: string) => {
  85. // console.log("urlToFile")
  86. // return urlToBlob(url).then(blob => {
  87. // if (!blob) return null;
  88. // return new File([blob], fileName, {
  89. // type: blob.type,
  90. // lastModified: new Date().getTime()
  91. // });
  92. // }).catch(error => {
  93. // return null;
  94. // })
  95. // }