fix network

This commit is contained in:
JinJiangHuang
2026-03-10 21:37:51 +08:00
parent 76ed32ccf3
commit fac70d7496
7 changed files with 383 additions and 37 deletions
+56 -13
View File
@@ -218,6 +218,9 @@ struct CachedAsyncImage<Content: View, Placeholder: View>: View {
@ViewBuilder let placeholder: () -> Placeholder
@State private var loadedImage: PlatformImage?
@State private var loadFailed = false
private static var delayedRetryDelay: TimeInterval { 3.0 }
init(
url: URL?,
@@ -246,6 +249,7 @@ struct CachedAsyncImage<Content: View, Placeholder: View>: View {
}
.onDisappear {
loadedImage = nil
loadFailed = false
}
}
@@ -265,9 +269,17 @@ struct CachedAsyncImage<Content: View, Placeholder: View>: View {
guard !Task.isCancelled else { return }
ImageCache.shared.set(image, for: url)
loadedImage = image
loadFailed = false
} catch {
guard !Task.isCancelled else { return }
loadedImage = nil
if error.isNetworkConnectionError && !loadFailed {
loadFailed = true
try? await Task.sleep(nanoseconds: UInt64(Self.delayedRetryDelay * 1_000_000_000))
guard !Task.isCancelled else { return }
await loadImage()
}
}
}
}
@@ -307,33 +319,64 @@ final class ImageLoader {
self.session = URLSession(configuration: config)
}
private static let maxImageRetries = 1
private static let imageRetryDelay: TimeInterval = 1.0
func load(url: URL) async throws -> PlatformImage {
var request = URLRequest(url: url)
request.httpMethod = "GET"
// User-Agent
request.setValue(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
forHTTPHeaderField: "User-Agent"
)
// Referer
if let host = url.host {
request.setValue("https://\(host)/", forHTTPHeaderField: "Referer")
}
let (data, response) = try await session.data(for: request)
var lastError: Error = ImageLoadError.invalidData
let totalAttempts = Self.maxImageRetries + 1
// HTTP
if let httpResponse = response as? HTTPURLResponse,
!(200...299).contains(httpResponse.statusCode) {
throw ImageLoadError.httpError(httpResponse.statusCode)
for attempt in 0..<totalAttempts {
do {
try Task.checkCancellation()
let (data, response) = try await session.data(for: request)
if let httpResponse = response as? HTTPURLResponse,
!(200...299).contains(httpResponse.statusCode) {
let error = ImageLoadError.httpError(httpResponse.statusCode)
if Self.isRetryableImageError(error, statusCode: httpResponse.statusCode),
attempt < totalAttempts - 1 {
lastError = error
try await Task.sleep(nanoseconds: UInt64(Self.imageRetryDelay * 1_000_000_000))
continue
}
throw error
}
let maxPixelSize = thumbnailMaxPixelSize
guard let image = Self.decodeImage(data: data, maxPixelSize: maxPixelSize) else {
throw ImageLoadError.invalidData
}
return image
} catch is CancellationError {
throw CancellationError()
} catch {
lastError = error
if error.isNetworkConnectionError && attempt < totalAttempts - 1 {
try? await Task.sleep(nanoseconds: UInt64(Self.imageRetryDelay * 1_000_000_000))
continue
}
if attempt >= totalAttempts - 1 { throw error }
}
}
let maxPixelSize = thumbnailMaxPixelSize
guard let image = Self.decodeImage(data: data, maxPixelSize: maxPixelSize) else {
throw ImageLoadError.invalidData
}
return image
throw lastError
}
private static func isRetryableImageError(_ error: Error, statusCode: Int) -> Bool {
[408, 429, 500, 502, 503, 504].contains(statusCode)
}
var cacheUsage: (memory: Int, disk: Int) {