无法在网络调用中返回可观察到的 customError

Posted

技术标签:

【中文标题】无法在网络调用中返回可观察到的 customError【英文标题】:can't return observable of customError in network call 【发布时间】:2018-10-15 11:16:54 【问题描述】:

我想使用 catchError 将我的错误恢复为自定义类型。 起初,我希望我的网络层返回 Observable,然后在 ViewModel 中订阅了 .OnNext、.OnError、.OnCompleted 事件,但我不知道应该如何处理诸如 4xx、5xx 网络状态码之类的错误,然后,他们返回我的自定义错误对象!

我的登录视图模型:

func getAccessToken()         
        let network = NetworkRequest()

        network.logInRequest(tokenType: .guest, token: "cce577f6021608", secondKey: "09128147040", client: "cce577f6021608bc31424d209cbf5120c3683191").subscribe(onNext:  loginData in
            self.token.onNext(loginData.access_token)
        , onError:  error in
            print("The Error is: \(error.localizedDescription)")
        , onCompleted: 
            print("Its Completed")
        ).disposed(by: bag)
    

我的网络层函数:

class NetworkRequest: NSObject 
    var rxProvider: MoyaProvider<WebServiceAPIs>

    override init() 
        rxProvider = MoyaProvider<WebServiceAPIs>( plugins: [ NetworkLoggerPlugin(verbose:true) ])
    

    func logInRequest(tokenType: accessTokenTypeEnum, token: String, secondKey: String, client: String) -> Observable<LoginModel> 
        return rxProvider.rx
              .request(WebServiceAPIs.getAccessToken(tokenType: tokenType.rawValue, token: token, secondKey: secondKey, client: client))
              .filterSuccessfulStatusCodes()
              .catchError( error -> Observable<NetworkError> in
                return //Observable.just() => I want to return a custom network error as obserable 
              )
              .map(LoginModel.self, atKeyPath: nil, using: JSONDecoder(), failsOnEmptyData: true).asObservable()
    


感谢您的帮助

【问题讨论】:

【参考方案1】:

根据我的经验,'.materialize()' 运算符是处理 HTTP 错误的完美解决方案。 您将获得一个单独的包装器事件,而不是单独的成功和错误事件,其中嵌套了成功或错误。

【讨论】:

在adamborek.com/how-to-handle-errors-in-rxswift 页面上搜索“materialize” - 有一个非常适合您的案例的示例(恕我直言)。【参考方案2】:

Moya 在错误块中返回 MoyaError 枚举,您可以通过使用打开 MoyaError 的开关提取错误类型然后使用 statusCode 转换为 NetworkError 枚举来处理它

func logInRequest(tokenType: accessTokenTypeEnum, token: String, secondKey: String, client: String) -> Observable<LoginModel> 
        return sharedProvider.rx
                .request(WebServiceAPIs.getAccessToken(tokenType: tokenType.rawValue, token: token, secondKey: secondKey, client: client))
                .filterSuccessfulStatusCodes()
                .catchError( [weak self] error -> Observable<NetworkError> in
                    guard let strongSelf = self else  return Observable.empty() 
                    if let moyaError = error as? MoyaError 
                        let networkError = self?.createNetworkError(from: moyaError)
                        return Observable.error(networkError)
                     else 
                        return Observable.error(NetworkError.somethingWentWrong(error.localizedDescription))
                    
                )
                .map(LoginModel.self, atKeyPath: nil, using: JSONDecoder(), failsOnEmptyData: true).asObservable()
    

    func createNetworkError(from moyaError: MoyaError) -> NetowrkError 
        switch moyaError 
        case .statusCode(let response):
            return NetworkError.mapError(statusCode: response.statusCode)
        case .underlying(let error, let response):
            if let response = response 
                return NetworkError.mapError(statusCode: response.statusCode)
             else 
                if let nsError = error as? NSError 
                  return NetworkError.mapError(statusCode: nsError.code)
                 else 
                  return NetworkError.notConnectedToInternet
                
            
         default:
              return NetworkError.somethingWentWrong("Something went wrong. Please try again.")
        
    

您可以创建自定义 NetworkError 枚举,如下所示,它将 statusCode 映射到自定义 NetworkError 枚举值。它将具有 errorDescription var,它将返回自定义描述以显示在错误视图中

enum NetworkError: Swift.Error 
    case unauthorized
    case serviceNotAvailable
    case notConnectedToInternet
    case somethingWentWrong(String)

    static func mapError(statusCode: Int) -> NetworkError 
        switch statusCode 
        case 401:
            return .unauthorized
        case 501:
            return .serviceNotAvailable
        case -1009:
            return .notConnectedToInternet
        default:
            return .somethingWentWrong("Something went wrong. Please try again.")
        
    

    var errorDescription: String 
        switch self 
        case .unauthorized:
            return "Unauthorised response from the server"
        case .notConnectedToInternet:
            return "Not connected to Internet"
        case .serviceNotAvailable:
            return "Service is not available. Try later"
        case .somethingWentWrong(let errorMessage):
            return errorMessage
        
    

【讨论】:

以上是关于无法在网络调用中返回可观察到的 customError的主要内容,如果未能解决你的问题,请参考以下文章

在模板中使用异步管道可观察到的不适用于单个值

在 ViewController 中可观察到的单元测试 RxSwift

从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)

可观察到的相同值的返回列表

管道操作符时如何返回可观察到的`forkJoin`

已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数