使用 SwiftUI 组合刷新令牌 [英] Refresh token with SwiftUI Combine

查看:32
本文介绍了使用 SwiftUI 组合刷新令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Swift 5 和适用于 iOS 的组合框架中实施刷新令牌策略.

I'm trying to implement a refresh token strategy in Swift 5 and the Combine Framework for iOS.

我不打算使用任何第三方包,只使用框架提供的`URLSession.dataTaskPublisher`,所以我的目标是:

I don't plan on using any third party package, just using what is provided by the framework, `URLSession.dataTaskPublisher`, so mu goal is to :

  1. 提出请求
  2. 如果请求失败并返回 401,则刷新 auth 令牌(这是另一个请求)
  1. Make a request
  2. If the request fails with 401, refresh the auth token (which is another request)
  1. 刷新令牌完成后,重试第一个请求
  2. 如果失败,则抛出由调用者处理的错误

这是一个非常简单的用例,但似乎很难在 Combine 中实现,这使得它在任何现实生活场景中都很难使用.

This is a very trivial use case, but seems to be very hard to implement in Combine, that makes it really hard to use in any real life scenario.

欢迎任何帮助!

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

This is my try, which unfortonately doesn't work

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 此处.这使您可以将错误替换为另一个发布者(例如,将错误 401 替换为刷新请求后跟 map switchToLastest 身份验证请求)或另一个错误(在这种情况下,如果它不是 401 然后只是抛出原始错误).

You should use the .tryCatch method on Publisher here. This lets you replace an error with another publisher (such as replacing error 401 with a refresh request followed by a map switchToLastest auth request) or with another error (in this case if its not a 401 then just throw the original error).

请注意,您可能不应该在这里使用 flatMap,因为它与 Rx 或 .flatmap(.latest) 中的 .flatMapLatest 不同代码> 在反应式 Swift 中.您想养成在Combine 中使用.mapswitchToLatest 的习惯(即apple 决定扁平化和映射是两个独立的操作符).如果您不这样做,您将在某些生成多个内部发布者的地方遇到麻烦,例如在您键入时搜索,因为您将获得所有这些,而不是获取最新的内部值,因为网络请求在不确定的时间内完成.

Note that you probably shouldn't be using flatMap here because its not the same as .flatMapLatest in Rx or .flatmap(.latest) in Reactive Swift. You want to get into the habit of using .map and switchToLatest in Combine (ie apple decided the flattening and the mapping are two separate operators). If you don't do this you will get into trouble in some places that generate more than one inner publisher, such as search while you type, because instead of getting the latests inner value you will get ALL of them, in arbitrary order since the network requests complete in indeterminate time.

这篇关于使用 SwiftUI 组合刷新令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆