【问题标题】:Alamofire returns .Success on error HTTP status codesAlamofire 在错误 HTTP 状态码上返回 .Success
【发布时间】:2016-04-16 17:00:35
【问题描述】:

我有一个非常简单的场景,我正在努力解决。我正在使用 Alamofire 在休息 API 上注册用户。第一次调用注册成功,用户可以登录。第二次调用,当尝试使用相同的电子邮件地址进行注册时,应该会导致来自服务器的 HTTP 状态代码 409。然而,Alamofire 返回一个带有空请求和响应的 .Success。我已经用邮递员测试了这个 API,它正确返回了 409。

为什么 Alamofire 没有返回 .Failure(error),错误包含状态码信息等?

这是我每次使用相同输入运行的调用。

Alamofire.request(.POST, "http://localhost:8883/api/0.1/parent", parameters: registrationModel.getParentCandidateDictionary(), encoding: .JSON).response(completionHandler: { (req, res, d, e) -> Void in
        print(req, res, d, e)
    })

【问题讨论】:

    标签: ios swift alamofire


    【解决方案1】:

    来自 Alamofire manual

    验证

    默认情况下,Alamofire 将任何已完成的请求视为成功, 无论响应的内容如何。在 a 之前调用 validate 如果响应有,响应处理程序会导致生成错误 不可接受的状态代码或 MIME 类型。

    您可以再次使用手册中的validate 方法手动验证状态代码:

    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
         .validate(statusCode: 200..<300)
         .validate(contentType: ["application/json"])
         .response { response in
             print(response)
         }
    

    或者您可以使用不带参数的validate 半自动验证状态代码和内容类型:

    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
         .validate()
         .responseJSON { response in
             switch response.result {
             case .success:
                 print("Validation Successful")
             case .failure(let error):
                 print(error)
             }
         }
    

    【讨论】:

    • 手册页链接指向 Alamofire 主页。正确的:Validation
    • 更新了链接。谢谢@andriy_fedin
    【解决方案2】:

    如果使用response,可以查看NSHTTPURLResponse参数:

    Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
        .response { response in
            if response.response?.statusCode == 409 {
                // handle as appropriate
            }
    }
    

    默认情况下,4xx 状态码不被视为错误,但您可以使用validate 将其视为错误,然后将其折叠到更广泛的错误处理中:

    Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
        .validate()
        .response() { response in
            guard response.error == nil else {
                // handle error (including validate error) here, e.g.
    
                if response.response?.statusCode == 409 {
                    // handle 409 here
                }
                return
            }
            // handle success here
    }
    

    或者,如果使用responseJSON

    Alamofire.request(urlString, method: .post, parameters: registrationModel.getParentCandidateDictionary(), encoding: JSONEncoding.default)
    .validate()
    .responseJSON() { response in
        switch response.result {
        case .failure:
            // handle errors (including `validate` errors) here
    
            if let statusCode = response.response?.statusCode {
                if statusCode == 409 {
                    // handle 409 specific error here, if you want
                }
            }
        case .success(let value):
            // handle success here
            print(value)
        }
    }
    

    以上是 Alamofire 4.x。请参阅 earlier versions of Alamofire 的此答案的先前版本。

    【讨论】:

    • if statusCode == 409 { // handle 409 specific error here, if you want } 行 - 从服务器端检索错误消息的最佳方法是什么?例如返回错误 401 和服务器通知用户登录凭据不正确。最佳做法是什么?
    • @luke - 通常你只需使用状态码。 Web 服务通常在响应正文中包含一些文本(例如,在 Alamofire 4.x 中,在 response.data 中),但是 AFAIK 的格式不是标准化的,因此您必须检查来自特定服务器的响应看看你能解析出什么,如果有的话。如果你不想经历所有这些,你可以只看statusCode 一个人。顺便说一句,请注意并非所有身份验证错误都会导致 401 状态代码,而是会导致错误,您必须查看 Error 对象的 code
    【解决方案3】:

    如果你使用 validate() 你会丢失来自服务器的错误信息,如果你想保留它,看这个答案https://stackoverflow.com/a/36333378/1261547

    【讨论】:

      【解决方案4】:

      这是我的 AlamoFire 错误捕获代码:

      switch response.result {
                      case .success(let value):
                          completion(.success(value))
                      case .failure(var error):
      
                          var errorString: String?
      
                          if let data = response.data {
                              if let json = try? (JSONSerialization.jsonObject(with: data, options: []) as! [String: String]) {
                                  errorString = json["error"]
      
                              }
                          }
                          let error = MyError(str: errorString!)
                          let x = error as Error
                          print(x.localizedDescription)
                          completion(.failure(x))
      
                      }
      

      和 MyError 类定义:

      class MyError: NSObject, LocalizedError {
              var desc = ""
              init(str: String) {
                  desc = str
              }
              override var description: String {
                  get {
                      return "MyError: \(desc)"
                  }
              }
              //You need to implement `errorDescription`, not `localizedDescription`.
              var errorDescription: String? {
                  get {
                      return self.description
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-05
        • 2016-02-07
        • 2015-05-12
        • 1970-01-01
        • 2012-11-14
        • 1970-01-01
        • 2017-02-20
        相关资源
        最近更新 更多