使用SwiftUI联合收割机刷新令牌

使用SwiftUI联合收割机刷新令牌,swift,swiftui,combine,Swift,Swiftui,Combine,我正在尝试在Swift 5和iOS的Combine框架中实现刷新令牌策略 我不打算使用任何第三方软件包,只使用框架“URLSession.dataTaskPublisher”提供的软件包,因此mu的目标是: 提出请求 如果401请求失败,请刷新身份验证令牌(这是另一个请求) 刷新令牌完成后,重试第一个请求 如果失败,则抛出由调用方处理的错误 ​ 这是一个非常简单的用例,但似乎很难在Combine中实现,这使得它很难在任何实际场景中使用 欢迎任何帮助 ​ 这是我的尝试,不幸的是,它不起作用 pr

我正在尝试在Swift 5和iOS的Combine框架中实现刷新令牌策略

我不打算使用任何第三方软件包,只使用框架“URLSession.dataTaskPublisher”提供的软件包,因此mu的目标是:

  • 提出请求
  • 如果401请求失败,请刷新身份验证令牌(这是另一个请求)
  • 刷新令牌完成后,重试第一个请求
  • 如果失败,则抛出由调用方处理的错误
  • 这是一个非常简单的用例,但似乎很难在Combine中实现,这使得它很难在任何实际场景中使用

    欢迎任何帮助

    这是我的尝试,不幸的是,它不起作用

    private func dataTaskPublisherWithAuth(for request: URLRequest) -> URLSession.DataTaskPublisher {
        return session.dataTaskPublisher(for: request)
    
            .tryCatch { error -> URLSession.DataTaskPublisher in
    guard error.errorCode == 401 else {
    throw error
    }
    var components = URLComponents(url: self.baseUrl, resolvingAgainstBaseURL: true)
    components?.path += "/refresh"
    components?.queryItems = [
    URLQueryItem(name: "refresh_token", value: KeychainHelper.RefreshToken),
    ]
    
    let url = components?.url
    var loginRequest = URLRequest(url: url!)
    loginRequest.httpMethod = "GET"
    loginRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    return session.dataTaskPublisher(for: loginRequest)
    .decode(type: LoginResponse.self, decoder: JSONDecoder())
    .map { result in
    if result.accessToken != nil {
    // Save access token
    KeychainHelper.AccessToken = result.accessToken!
    KeychainHelper.RefreshToken = result.refreshToken!
    KeychainHelper.ExpDate = Date(timeIntervalSinceNow: TimeInterval(result.expiresIn!))
    }
    return result
    }
    .flatMap { data -> URLSession.DataTaskPublisher in
    session.dataTaskPublisher(for: request)
    }
        }.eraseToAnyPublsiher()
    
    }
    

    您应该在Publisher上使用
    .tryCatch
    方法。这允许您将错误替换为另一个发布服务器(例如将错误401替换为刷新请求,后跟
    map
    switchToLastestauth请求)或另一个错误(在这种情况下,如果不是401,则只抛出原始错误)


    请注意,此处可能不应使用
    flatMap
    ,因为它与Rx中的
    .flatMapLatest
    或反应式Swift中的
    .flatMap(.latest)
    不同。您希望养成在联合收割机中使用
    .map
    switchToLatest
    的习惯(即苹果决定展平和映射是两个独立的操作符)。如果不这样做,您将在一些生成多个内部发布服务器的地方遇到麻烦,例如键入时进行搜索,因为不是获取最新的内部值,而是以任意顺序获取所有内部值,因为网络请求在不确定的时间内完成

    我试图实现完全相同的用例。我可以问一下你是否成功地做到了这一点吗?我有一个类似的问题,如果你能看一下,让我知道我的方法有什么问题,我会非常感激。