我已经使用异步创建了一个通用网络功能,该功能工作正常,但我希望能够在抛出错误(例如 token 过期)时重试该请求。我该如何做到这一点而不需要更改我所有的 DO Catch?
func request<T: Codable>(_ endpoint: Endpoint) async throws -> T {
guard let url = endpoint.url else {
throw NetworkError.badURL
}
guard let token = idToken else {
throw NetworkError.invalidToken
}
let request = buildRequest(from: url, methodType: endpoint.methodType, idToken: token)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
//RETRY X AMOUNT OF TIMES <<<
throw NetworkError.invalidResponse
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let result = try? decoder.decode(T.self, from: data) else {
throw NetworkError.decodingError
}
print("Result: \(result)")
return result
}
最佳答案
如果您想这样做,我建议编写一个包装重试逻辑的 data(for:delegate:)
的再现,例如:
extension URLSession {
func data(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil, maxRetries: Int) async throws -> (Data, URLResponse) {
for _ in 0 ..< maxRetries {
let (data, response) = try await data(for: request, delegate: delegate)
guard let response = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if 200..<300 ~= response.statusCode { // as an aside, note, any 2xx response is success
return (data, response)
}
}
throw NetworkError.invalidResponse
}
}
然后,您可以替换:
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
//RETRY X AMOUNT OF TIMES <<<
throw NetworkError.invalidResponse
}
与:
let (data, response) = try await URLSession.shared.data(for: request, maxRetries: 3)
关于快速异步网络。出现错误时如何重试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75081648/