最新消息:20210917 已从crifan.com换到crifan.org

[已解决]如何让Alamofire在http加了validate之后再去responseJSON返回是出错的时候可以获取对应的错误信息

iOS crifan 2380浏览 0评论

之前已经实现了:

[已解决]Swift中Alamofire的http返回401时默认属于Success而不是Failure

所以代码改为:

func getRequestRespJson(httpRequest:Alamofire.Request, mergedAllPara:Dictionary<String, AnyObject>, respJsonHandler: (Alamofire.Result<JSON, NSError>, mergedAllPara:Dictionary<String, AnyObject>) -> Void) {
    gLog.info(“httpRequest=\(httpRequest), mergedAllPara=\(mergedAllPara), respJsonHandler=\(respJsonHandler)”)
    dispatchBackground_async({
//        httpRequest.responseJSON(queue: BackgroundThread, completionHandler: { response in
        //validate will make it to error for which status code is not within 200…299
        httpRequest.validate().responseJSON(queue: BackgroundThread, completionHandler: { response in
            gLog.debug(“request=\(response.request), response=\(response.response), statusCode=\(response.response?.statusCode), result=\(response.result)”)
            /*
            [Debug] [com.apple.root.background-qos] [CrifanLibHttp.swift:21]
            request=Optional(<NSMutableURLRequest: 0x7964c340> { URL: http://qapp.chinacloudapp.cn/open/code }), response=Optional(<NSHTTPURLResponse: 0x78f82160> { URL: http://qapp.chinacloudapp.cn/open/code } { status code: 200, headers {
                 Connection = “keep-alive”;
                 “Content-Length” = 48;
                 “Content-Type” = “application/json;charset=UTF-8”;
                 Date = “Fri, 03 Jun 2016 08:42:18 GMT”;
                 Server = “nginx/1.10.1”;
                 } }), statusCode=Optional(200), result=SUCCESS
             */
            let statusCode = response.response?.statusCode ?? 0
            gLog.debug(“statusCode=\(statusCode)”)
            //2016-06-15 20:32:10.878 [Verbose] [com.apple.root.background-qos] [CrifanLibHttp.swift:76] getUrlRespJson_async(_:url:parameters:headers:extraPara:respJsonHandler:) > statusCode=200
            gLog.verbose(“HTTPMethod=\(response.request?.HTTPMethod), URL=\(response.request?.URL), URLString=\(response.request?.URLString), allHTTPHeaderFields=\(response.request?.allHTTPHeaderFields))”)
            if let httpBodyData = response.request?.HTTPBody {
                let httpBodyJson = JSON(data: httpBodyData)
                gLog.verbose(“httpBodyJson=\(httpBodyJson)”)
                //httpBodyJson=unknown
                /*
                httpBodyJson={
                  “customer” : {
                    “followup” : 4,
                    “datafrom” : 2,
                    “phone” : “”,
                    “name” : “”,
                    “topComeFrom” : 0,
                    “salesId” : 10000010,
                    “testdrive” : true,
                    “comeFrom” : 0
                  },
                  “intentedcar” : {
                    “color” : “0”,
                    “spec” : “0”,
                    “series” : “0”
                  }
                }
                 */
            }
            switch response.result {
            case .Success(let value):
                gLog.verbose(“value=\(value), value type=\(String(value.dynamicType)))”)
                /*
                value={
                    code = 200;
                    data = 13812345678;
                    message = ok;
                }, value type=__NSCFDictionary)
                 */
                let valueJson = JSON(value)
                gLog.verbose(“valueJson=\(valueJson)”)
                respJsonHandler(Alamofire.Result.Success(valueJson), mergedAllPara: mergedAllPara)
            case .Failure(let error):
                /*
                 {
                    “message” : “Unauthorized”,
                    “code” : 401
                 }
                 */
                var errorStr:String = error.localizedDescription
                if errorStr.isEmpty {
                    errorStr = error.localizedFailureReason ?? “”
                }
                gLog.error(“\(httpRequest) error: \(errorStr), detail:\(error)”)
                //GET http://qapp.chinacloudapp.cn/token/generate error: The data couldn’t be read because it isn’t in the correct format., detail:Error Domain=NSCocoaErrorDomain Code=3840 “Invalid value around character 0.” UserInfo={NSDebugDescription=Invalid value around character 0.}
                //GET http://qapp.chinacloudapp.cn:8090/app/statistics/10000005/customer/analysis (401) error: 未能完成该操作。Response status code was unacceptable: 401, detail:Error Domain=com.alamofire.error Code=-6003 “Response status code was unacceptable: 401” UserInfo={StatusCode=401, NSLocalizedFailureReason=Response status code was unacceptable: 401}
                //let error:NSError = NSError(domain: HttpErrorDomain, code: statusCode, userInfo: [
                let returnError:NSError = NSError(domain: error.domain, code: error.code, userInfo: [
                    “message”   : errorStr,
                    “code”      : statusCode,
                    “NSDebugDescription” : error.userInfo[“NSDebugDescription”] ?? “”,
                    ])
                updateAccessTokenIfUnauthoried(returnError)
                respJsonHandler(Alamofire.Result.Failure(returnError), mergedAllPara: mergedAllPara)
            }
        })
    })
}

但是现在遇到一个问题:

当服务器端返回错误,比如403,内部是给了详细的错误信息的

比如是:

            {
              “message” : “手机号码已经注册|403105”,
              “code” : 403
            }

然后内部代码可以提取出来对应的,返回的json中的message中的错误信息,提醒给用户

但是,此时,对于:

httpRequest.validate()

之后,再去:responseJSON

虽然可以进入:

case .Failure(let error):

检测到statusCode是403

但是那些json错误信息,却拿不到了。

现在希望实现的是:

在使用了httpRequest.validate().responseJSON

在服务器端返回403的错误的同时,还可以获取到对应的错误的json信息

参考:

Alamofire/Alamofire: Elegant HTTP Networking in Swift

去试试

Alamofire.request(.GET, “https://httpbin.org/get”)
         .validate()
         .responseString { response in
             print(“Response String: \(response.result.value)”)
         }
         .responseJSON { response in
             print(“Response JSON: \(response.result.value)”)
         }

不过没继续试上述办法。

然后看到另外的:

Creating a Custom Response Serializer

感觉好像是需要自己重新写reponse的序列化

不过,最后的最后,找到了解决办法:

当出错的时候,response,是有data的,可以被解析为所收到的json

此处就是我们要的json了,比如:

{
  “message” : “手机号码已经注册|403105”,
  “code” : 403
}

然后再去写代码去解析:

完整代码是:

            case .Failure(let error):
                /*
                 {
                    “message” : “Unauthorized”,
                    “code” : 401
                 }
                 */
                var returnError = NSError(domain: “”, code: 0, userInfo: nil)
                var parseRespJsonOk = false
                if let respData = response.data {
                    let respJson = JSON(data: respData)
                    gLog.verbose(“respJson=\(respJson)”)
                    let parsedError = parseRespError(respJson)
                    gLog.debug(“parsedError=\(parsedError)”)
                    if parsedError.parseOk {
                        returnError = parsedError.parsedError
                        parseRespJsonOk = true
                    }
                }
                if !parseRespJsonOk {
                    var errorStr:String = error.localizedDescription
                    if errorStr.isEmpty {
                        errorStr = error.localizedFailureReason ?? “”
                    }
                    gLog.error(“\(httpRequest) error: \(errorStr), detail:\(error)”)
                    //GET http://qapp.chinacloudapp.cn/token/generate error: The data couldn’t be read because it isn’t in the correct format., detail:Error Domain=NSCocoaErrorDomain Code=3840 “Invalid value around character 0.” UserInfo={NSDebugDescription=Invalid value around character 0.}
                    //GET http://qapp.chinacloudapp.cn:8090/app/statistics/10000005/customer/analysis (401) error: 未能完成该操作。Response status code was unacceptable: 401, detail:Error Domain=com.alamofire.error Code=-6003 “Response status code was unacceptable: 401” UserInfo={StatusCode=401, NSLocalizedFailureReason=Response status code was unacceptable: 401}
                    returnError = NSError(domain: error.domain, code: error.code, userInfo: [
                        “message”   : errorStr,
                        “code”      : statusCode,
                        “NSDebugDescription” : error.userInfo[“NSDebugDescription”] ?? “”,
                        ])
                }
                updateAccessTokenIfUnauthoried(returnError)
                respJsonHandler(Alamofire.Result.Failure(returnError), mergedAllPara: mergedAllPara)
            }
/*
respJson={
  “message” : “手机号码已经注册|403105”,
  “code” : 403
}
*/
func parseRespError(respJson:JSON) -> (parseOk:Bool, parsedError:NSError) {
    gLog.verbose(“respJson=\(respJson)”)
    var parseOk = false
    var parsedError = NSError(domain: “”, code: 0, userInfo: nil)
    guard let statusCode = respJson[“code”].int else {
        gLog.debug(“not found response code for respJson=\(respJson)”)
        return (parseOk, parsedError)
    }
    gLog.debug(“statusCode=\(statusCode)”)
    guard let message = respJson[“message”].string else {
        gLog.debug(“not found response message for respJson=\(respJson)”)
        return (parseOk, parsedError)
    }
    gLog.debug(“message=\(message)”)
    //parse message to message + subCode
    let messageStrArr = message.splitToStrArr(“|”)
    var messageStr:String = message
    var subCode:Int = 0
    guard messageStrArr.count >= 2 else {
        gLog.error(“can not parse response message=\(message) to sub array”)
        return (parseOk, parsedError)
    }
    gLog.verbose(“messageStrArr=\(messageStrArr)”)
    //messageStrArr=[“手机号码已经注册”, “403105”]
    parseOk = true
    messageStr = messageStrArr[0]
    subCode = Int(messageStrArr[1]) ?? 0
    parsedError = NSError(domain: HttpErrorDomain, code: statusCode, userInfo: [
        “message”   : messageStr,
        “code”      : statusCode,
        “subCode”   : subCode,
        ])
    return (parseOk, parsedError)
}

即可满足此处的需求了。

[总结]

当Alamofire的httpRequest在validate之后再去responseJSON:

httpRequest.validate().responseJSON

此处得到的结果中,如果是Failure,则此时是可以通过

解析response.data而得到对应的返回的json信息的

其中就有此处我们所需要的错误信息了。

而无需额外的去写自定义的response的JSON序列化了。

转载请注明:在路上 » [已解决]如何让Alamofire在http加了validate之后再去responseJSON返回是出错的时候可以获取对应的错误信息

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
100 queries in 0.203 seconds, using 23.33MB memory