Refre sh токен с SwiftUI Combine - PullRequest
       6

Refre sh токен с SwiftUI Combine

1 голос
/ 13 января 2020

Я пытаюсь реализовать стратегию refre sh token в Swift 5 и Combine Framework для iOS.

. Я не планирую использовать какой-либо сторонний пакет, просто использую то, что предоставляемые фреймворком `URLSession.dataTaskPublisher`, поэтому цель состоит в том, чтобы:

  1. Сделать запрос
  2. Если запрос не выполнен с 401, обновить sh токен аутентификации ( это еще один запрос)
    1. После того, как токен refre sh завершен, повторите первый запрос
    2. Если он не сработает, выведите ошибку, которая будет обработана вызывающей стороной

Это очень тривиальный вариант использования, но, кажется, его очень сложно реализовать в 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()

}

1 Ответ

2 голосов
/ 14 января 2020

Вы должны использовать метод .tryCatch на Publisher здесь . Это позволяет заменить ошибку другим издателем (например, заменить ошибку 401 запросом refre sh с последующим запросом map switchToLastest auth) или другой ошибкой (в данном случае, если это не 401, тогда просто выбросить оригинальная ошибка).

Обратите внимание, что вам, вероятно, не следует использовать flatMap здесь, потому что это не то же самое, что .flatMapLatest в Rx или .flatmap(.latest) в Reactive Swift. Вы хотите привыкнуть к использованию .map и switchToLatest в Combine (ie apple решила, что выравнивание и отображение - это два отдельных оператора). Если вы этого не сделаете, то в некоторых местах возникнут проблемы, которые приводят к появлению более одного внутреннего издателя, например, поиск во время ввода текста, потому что вместо получения внутреннего последнего значения вы получите ВСЕ из них в произвольном порядке, так как сетевые запросы завершаются за неопределенное время.

...