gpt4 book ai didi

ios - 使用Combine Publishers的401重试机制

转载 作者:行者123 更新时间:2023-12-01 15:55:09 27 4
gpt4 key购买 nike

对结合相当新。
使用访问 token 和刷新 token 的常见场景。

你得到一个 401,你需要在重试初始调用之前处理它(调用一些服务来刷新 token )

func dataLoader(backendURL: URL) -> AnyPublisher<Data, Error> {
let request = URLRequest(url: backendURL)
return dataPublisher(for: request)
// We get here when a request fails
.tryCatch { (error) -> AnyPublisher<(data: Data, response: URLResponse), URLError> in
guard error.errorCode == 401 else { // UPS - Unauthorized request
throw error
}

// We need to refresh token and retry -> HOW?
// And try again
// return dataPublisher(for: request)
}
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {

throw CustomError.invalidServerResponse
}
return data
}
.eraseToAnyPublisher()
}

我将如何包装这个“ token 刷新服务”?

最佳答案

您的代码提到了“ token ”,但您没有解释那是什么。假设您有一个 token 类型:

struct Token: RawRepresentable {
var rawValue: String
}

假设您有一个函数通过返回新 token 的发布者异步获取新 token :
func freshToken() -> AnyPublisher<Token, Error> {
// Your code here, probably involving a URL request/response...
fatalError()
}

假设您通过将一些 URL 与 token 组合来生成数据的 URL 请求:
func backendRequest(with url: URL, token: Token) -> URLRequest {
// Your code here, to somehow combine the url and the token into the real ...
fatalError()
}

现在,如果响应是 404,您想重试请求,每次使用新 token 。您可能应该限制尝试次数。所以让我们编写函数来取 triesLeft数数。如 triesLeft > 1并且响应是 404,它将要求一个新的 token 并使用它再次调用自己( triesLeft 递减)。

目标变得更加复杂,因为 URLSession.DataTaskPublisher不会将 404 响应变成错误。它将其视为正常输出。

所以我们将使用嵌套的辅助函数来处理 DataTaskPublisher 的输出。 ,这样我们就不会在闭包中嵌套这么多代码。辅助函数,名为 publisher(forDataTaskOutput:) , 根据响应决定做什么。
  • 如果响应是代码为 200 的 HTTP 响应,则它只返回数据。请注意,它必须返回一个发布者,其 FailureError ,所以它使用 Result.Pubilsher让 Swift 推导出 Failure类型。
  • 如果响应是带有代码 404 和 triesLeft > 1 的 HTTP 响应,它调用 freshToken并使用 flatMap将其链接到对外部函数的另一个调用中。
  • 否则,它会产生错误 CustomError.invalidServerResponse 的失败.

  • func data(atBackendURL url: URL, token: Token, triesLeft: Int) -> AnyPublisher<Data, Error> {
    func publisher(forDataTaskOutput output: URLSession.DataTaskPublisher.Output) -> AnyPublisher<Data, Error> {
    switch (output.response as? HTTPURLResponse)?.statusCode {
    case .some(200):
    return Result.success(output.data).publisher.eraseToAnyPublisher()
    case .some(404) where triesLeft > 1:
    return freshToken()
    .flatMap { data(atBackendURL: url, token: $0, triesLeft: triesLeft - 1) }
    .eraseToAnyPublisher()
    default:
    return Fail(error: CustomError.invalidServerResponse).eraseToAnyPublisher()
    }
    }

    let request = backendRequest(with: url, token: token)
    return URLSession.shared.dataTaskPublisher(for: request)
    .mapError { $0 as Error }
    .flatMap(publisher(forDataTaskOutput:))
    .eraseToAnyPublisher()
    }

    关于ios - 使用Combine Publishers的401重试机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61557327/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com