tsk*_*bru 16 ios swift alamofire rx-swift moya
我在如何使用moya和rxswift刷新oauth令牌时找到了这个例子,我必须稍微修改才能编译.这段代码适用于我的场景80%.它的问题是它将运行所有http错误,而不仅仅是401错误.我想要的是将我的所有其他http错误传递为错误,以便我可以处理其他地方而不是在这里吞下它们.
使用此代码,如果我得到一个HttpStatus 500,它将运行3次验证码,这显然不是我想要的.
我试图改变这个代码来处理只处理401错误,但似乎无论我做什么我都无法得到编译的代码.它总是抱怨错误的返回类型,"Cannot convert return expression of type Observable<Response> to return type Observable<Response>"这对我来说没有意义..
我想要的:处理401,但停止所有其他错误
import RxSwift
import KeychainAccess
import Moya
public extension ObservableType where E == Response {
/// Tries to refresh auth token on 401 errors and retry the request.
/// If the refresh fails, the signal errors.
public func retryWithAuthIfNeeded() -> Observable<E> {
return self.retryWhen {
(e: Observable<ErrorType>) in
return Observable.zip(e, Observable.range(start: 1, count: 3), resultSelector: { $1 })
.flatMap { i in
return AuthProvider.sharedInstance.request(
.LoginFacebookUser(
accessToken: AuthenticationManager.defaultInstance().getLoginTokenFromKeyChain(),
useFaceBookLogin: AuthenticationManager.defaultInstance().isFacebookLogin())
)
.filterSuccessfulStatusCodes()
.mapObject(Accesstoken.self)
.catchError {
error in
log.debug("ReAuth error: \(error)")
if case Error.StatusCode(let response) = error {
if response.statusCode == 401 {
// Force logout after failed attempt
log.debug("401:, force user logout")
NSNotificationCenter.defaultCenter().postNotificationName(Constants.Notifications.userNotAuthenticated, object: nil, userInfo: nil)
}
}
return Observable.error(error)
}.flatMapLatest({
token -> Observable<Accesstoken> in
AuthenticationManager.defaultInstance().storeServiceTokenInKeychain(token)
return Observable.just(token)
})
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
sol*_*ell 16
哪一行有编译错误?在我看来,这将是这条线:
.catchError {
error in
//...
return Observable.error(error) // is this the line causing the compilation error?
}
Run Code Online (Sandbox Code Playgroud)
如果是这样,那可能是因为catchError期望块返回Observable<Response>一个错误的情况下它可以继续,而不是一个Observable<ErrorType>.
在任何一种情况下,它都有助于使用更多类型来注释您的代码,以便您可以查明这样的问题,以及帮助Swift编译器,它通常无法自己解决这些类型的问题.所以这样的事情会对你有所帮助:
.catchError {
error -> Observable<Response> in
//...
return Observable.error(error) // Swift should have a more accurate and helpful error message here now
}
Run Code Online (Sandbox Code Playgroud)
请注意,我只是向您展示错误是什么以及如何让Xcode为您提供更好的错误消息.你想要归还的是不正确的.
401我不确定为什么你期望这个代码401区别对待(除了发布到通知中心和日志记录).实际上,你正在捕捉错误,但是你总是在结尾处返回Observable一个Error事件(return Observable.error(error)),所以它永远不会重试.
要401重试,您应该Observable从retryWhen块中返回一个,它将发送一个 Next事件(表示您要重试).对于所有其他状态代码,即Observable应发送Error(因为您目前正在做),这将意味着,你不希望重试,和你想的错误传播.
所以像这样:
.retryWhen { errorObservable -> Observable<ErrorType> in
log.debug("ReAuth error: \(error)")
if case Error.StatusCode(let response) = error where response.statusCode == 401 {
log.debug("401:, force user logout")
NSNotificationCenter.defaultCenter().postNotificationName(Constants.Notifications.userNotAuthenticated, object: nil, userInfo: nil)
// If `401`, then return the `Observable<ErrorType>` which was given to us
// It will emit a `.Next<ErrorType>`
// Since it is a `.Next` event, `retryWhen` will retry.
return errorObservable
}
else {
// If not `401`, then `flatMap` the `Observable<ErrorType>` which
// is about to emit a `.Next<ErrorType>` into
// an `Observable<ErrorType>` which will instead emit a `.Error<ErrorType>`.
// Since it is an `.Error` event, `retryWhen` will *not* retry.
// Instead, it will propagate the error.
return errorObservable.flatMap { Observable.error($0) }
}
}
Run Code Online (Sandbox Code Playgroud)