【问题标题】:Swift Alamofire: How to get the HTTP response status codeSwift Alamofire:如何获取 HTTP 响应状态码
【发布时间】:2015-05-21 18:43:18
【问题描述】:

我想检索请求失败的 HTTP 响应状态代码(例如 400、401、403、503 等)(理想情况下也是成功的)。在这段代码中,我正在使用 HTTP Basic 执行用户身份验证,并希望能够在用户输入错误密码时向用户发送身份验证失败的消息。

Alamofire.request(.GET, "https://host.com/a/path").authenticate(user: "user", password: "typo")
    .responseString { (req, res, data, error) in
        if error != nil {
            println("STRING Error:: error:\(error)")
            println("  req:\(req)")
            println("  res:\(res)")
            println("  data:\(data)")
            return
        }
        println("SUCCESS for String")
}
    .responseJSON { (req, res, data, error) in
        if error != nil {
            println("JSON Error:: error:\(error)")
            println("  req:\(req)")
            println("  res:\(res)")
            println("  data:\(data)")
            return
        }
        println("SUCCESS for JSON")
}

不幸的是,产生的错误似乎并不表明实际收到了 HTTP 状态代码 409:

STRING Error:: error:Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo=0x7f9beb8efce0 {NSErrorFailingURLKey=https://host.com/a/path, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://host.com/a/path})
  req:<NSMutableURLRequest: 0x7f9beb89d5e0> { URL: https://host.com/a/path }
  res:nil
  data:Optional("")
JSON Error:: error:Optional(Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo=0x7f9beb8efce0 {NSErrorFailingURLKey=https://host.com/a/path, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://host.com/a/path})
  req:<NSMutableURLRequest: 0x7f9beb89d5e0> { URL: https://host.com/a/path }
  res:nil
  data:nil

此外,如果发生错误,最好检索 HTTP 正文,因为我的服务器端会在其中放置错误的文本描述。

问题
是否可以在非 2xx 响应时检索状态码?
是否可以在 2xx 响应时检索特定的状态代码?
是否可以在非 2xx 响应时检索 HTTP 正文?

谢谢!

【问题讨论】:

  • 如果您未经身份验证,您会收到 -999 设计。不确定这是为什么或如何解决...您解决了吗?

标签: swift alamofire


【解决方案1】:

在您的responseJSON 补全中,您可以从响应对象中获取状态码,该对象的类型为NSHTTPURLResponse?

if let response = res {
    var statusCode = response.statusCode
}

无论状态码是否在错误范围内,这都会起作用。如需更多信息,请查看NSHTTPURLResponse documentation

对于您的其他问题,您可以使用responseString 函数获取原始响应正文。除了responseJSON 之外,您还可以添加它,两者都会被调用。

.responseJson { (req, res, json, error) in
   // existing code
}
.responseString { (_, _, body, _) in
   // body is a String? containing the response body
}

【讨论】:

    【解决方案2】:

    您的错误表明该操作由于某种原因被取消。我需要更多细节来理解为什么。但我认为更大的问题可能是由于您的端点https://host.com/a/path 是伪造的,因此没有真正的服务器响应来报告,因此您看到的是nil

    如果您找到提供正确响应的有效端点,您应该会看到 res 的非零值(使用 Sam 提到的技术),其形式为 NSURLHTTPResponse 对象,其属性类似于 @987654325 @等

    另外,为了清楚起见,error 的类型为 NSError。它告诉您网络请求失败的原因。服务器端失败的状态码实际上是响应的一部分。

    希望这有助于回答您的主要问题。

    【讨论】:

    • 很好,我太专注于底部的问题列表。
    • 它实际上收到了 401 Unauthorized 代码,因为我故意发送错误的密码来模拟用户输入错误的密码,以便我能够抓住这种情况并给用户反馈。那不是我使用的实际 URL,但我使用的是合法的 URL,当我发送正确的密码时会成功。我原始帖子中的控制台输出是点击真实 URL 的实际输出(除了 URL 是假的),您可以看到 res 对象是 nil,所以这个答案没有帮助,抱歉。
    • 感谢您的澄清。好吧,那么这里唯一值得怀疑的是我没有遇到过的 -999 错误,但是文档表明该请求正在被取消(因此,即使收到响应的问题也应该没有实际意义)。您是否尝试为与身份验证无关的不同类型的错误打印响应对象?只是好奇。
    • ahhhh 我以为error 指的是状态代码超出我们为validate() 提供的范围的响应。谢谢!!!
    【解决方案3】:

    对于使用 Alamofire > 2.0 的 Swift 2.0 用户

    Alamofire.request(.GET, url)
      .responseString { _, response, result in
        if response?.statusCode == 200{
          //Do something with result
        }
    }
    

    【讨论】:

      【解决方案4】:

      对于 Swift 3.x / Swift 4.0 / Swift 5.0 用户使用 Alamofire >= 4.0 / Alamofire >= 5.0


      response.response?.statusCode
      

      更详细的例子:

      Alamofire.request(urlString)
              .responseString { response in
                  print("Success: \(response.result.isSuccess)")
                  print("Response String: \(response.result.value)")
      
                  var statusCode = response.response?.statusCode
                  if let error = response.result.error as? AFError {  
                      statusCode = error._code // statusCode private                 
                      switch error {
                      case .invalidURL(let url):
                          print("Invalid URL: \(url) - \(error.localizedDescription)")
                      case .parameterEncodingFailed(let reason):
                          print("Parameter encoding failed: \(error.localizedDescription)")
                          print("Failure Reason: \(reason)")
                      case .multipartEncodingFailed(let reason):
                          print("Multipart encoding failed: \(error.localizedDescription)")
                          print("Failure Reason: \(reason)")
                      case .responseValidationFailed(let reason):
                          print("Response validation failed: \(error.localizedDescription)")
                          print("Failure Reason: \(reason)")
      
                          switch reason {
                          case .dataFileNil, .dataFileReadFailed:
                              print("Downloaded file could not be read")
                          case .missingContentType(let acceptableContentTypes):
                              print("Content Type Missing: \(acceptableContentTypes)")
                          case .unacceptableContentType(let acceptableContentTypes, let responseContentType):
                              print("Response content type: \(responseContentType) was unacceptable: \(acceptableContentTypes)")
                          case .unacceptableStatusCode(let code):
                              print("Response status code was unacceptable: \(code)")
                              statusCode = code
                          }
                      case .responseSerializationFailed(let reason):
                          print("Response serialization failed: \(error.localizedDescription)")
                          print("Failure Reason: \(reason)")
                          // statusCode = 3840 ???? maybe..
                      default:break
                      }
      
                      print("Underlying error: \(error.underlyingError)")
                  } else if let error = response.result.error as? URLError {
                      print("URLError occurred: \(error)")
                  } else {
                      print("Unknown error: \(response.result.error)")
                  }
      
                  print(statusCode) // the status code
          } 
      

      (Alamofire 4 包含一个全新的错误系统,详情请查看here

      对于 Swift 2.x 用户 Alamofire >= 3.0

      Alamofire.request(.GET, urlString)
            .responseString { response in
                   print("Success: \(response.result.isSuccess)")
                   print("Response String: \(response.result.value)")
                   if let alamoError = response.result.error {
                     let alamoCode = alamoError.code
                     let statusCode = (response.response?.statusCode)!
                   } else { //no errors
                     let statusCode = (response.response?.statusCode)! //example : 200
                   }
      }
      

      【讨论】:

      • 例如,response.result.error 可能会给您一个 Alamofire 错误。 StatusCodeValidationFailedFAILURE: Error Domain=com.alamofire.error Code=-6003。如果你真的想得到 HTTP 响应错误,最好是用户 response.response?.statusCode
      • @KostiantynKoval 我同意你的观点,你已经做了适当的澄清。为了清楚起见,我更新了我的答案
      • 为我工作... {let statusCode = response.response!.statusCode}
      【解决方案5】:
          Alamofire
              .request(.GET, "REQUEST_URL", parameters: parms, headers: headers)
              .validate(statusCode: 200..<300)
              .responseJSON{ response in
      
                  switch response.result{
                  case .Success:
                      if let JSON = response.result.value
                      {
                      }
                  case .Failure(let error):
          }
      

      【讨论】:

      • 这激发了 api 的最佳实践
      • URW :) 尝试为您的请求实现路由器。 ;)
      【解决方案6】:

      在下面带有参数response 的完成处理程序中,我发现http 状态代码在response.response.statusCode

      Alamofire.request(.POST, urlString, parameters: parameters)
                  .responseJSON(completionHandler: {response in
                      switch(response.result) {
                      case .Success(let JSON):
                          // Yeah! Hand response
                      case .Failure(let error):
                         let message : String
                         if let httpStatusCode = response.response?.statusCode {
                            switch(httpStatusCode) {
                            case 400:
                                message = "Username or password not provided."
                            case 401:
                                message = "Incorrect password for user '\(name)'."
                             ...
                            }
                         } else {
                            message = error.localizedDescription
                         }
                         // display alert with error message
                       }
      

      【讨论】:

      • 嗨,statusCode 200 会失败吗?我的请求在服务器端得到了正确处理,但响应属于失败
      • @perwyl 我不认为 200 是 http 错误:请参阅 stackoverflow.com/questions/27921537/…
      • @perwyl 状态码 200 表示成功,如果您的服务器返回 200 并且响应指示错误(即一些名为 issuccess = false 的属性),那么您必须在前端代码中处理它
      【解决方案7】:

      或者使用模式匹配

      if let error = response.result.error as? AFError {
         if case .responseValidationFailed(.unacceptableStatusCode(let code)) = error {
             print(code)
         }
      }
      

      【讨论】:

      • 工作就像一个魅力。
      • 只有错误被传递给视图而不是响应时有用
      【解决方案8】:

      使用 alamofire 获取状态码的最佳方式。

      Alamofire.request(URL).responseJSON { 回应 让状态 = response.response?.statusCode 打印(“状态\(状态)”) }

      【讨论】:

        【解决方案9】:

        您可以通过 alamofire 检查以下代码以获取状态码处理程序

            let request = URLRequest(url: URL(string:"url string")!)    
            Alamofire.request(request).validate(statusCode: 200..<300).responseJSON { (response) in
                switch response.result {
                case .success(let data as [String:Any]):
                    completion(true,data)
                case .failure(let err):
                    print(err.localizedDescription)
                    completion(false,err)
                default:
                    completion(false,nil)
                }
            }
        

        如果状态码未验证,则在switch case中进入失败

        【讨论】:

          【解决方案10】:

          我需要知道如何获取实际的错误代码号。

          我从其他人那里继承了一个项目,我必须从他们之前为 Alamofire 设置的 .catch 子句中获取错误代码:

          } .catch { (error) in
          
              guard let error = error as? AFError else { return }
              guard let statusCode = error.responseCode else { return }
          
              print("Alamofire statusCode num is: ", statusCode)
          }
          

          或者如果您需要从response 值中获取它,请关注@mbryzinski's answer

          Alamofire ... { (response) in
          
              guard let error = response.result.error as? AFError else { return }
              guard let statusCode = error.responseCode else { return }
          
              print("Alamofire statusCode num is: ", statusCode)
          })
          

          【讨论】:

            【解决方案11】:

            对于 Swift 3.x / Swift 4.0 / Swift 5.0 用户使用 Alamofire >= 5.0

            使用请求修饰符来增加和减少超时间隔。

            Alamofire 的 请求创建方法提供了最常用的自定义参数,但有时这些参数还不够。在创建请求时,可以通过使用 RequestModifier 闭包来修改从传递的值创建的 URLRequest。例如,要将 URLRequest 的 timeoutInterval 设置为 120 秒,请在闭包中修改请求。

            var manager = Session.default
             manager.request(urlString, method: method, parameters: dict, headers: headers, requestModifier: { $0.timeoutInterval = 120 }).validate().responseJSON { response in
            

            RequestModifiers 也适用于尾随闭包语法。

            var manager = Session.default
                 manager.request("https://httpbin.org/get") { urlRequest in
                urlRequest.timeoutInterval = 60
                urlRequest.allowsConstrainedNetworkAccess = false
            }
            .response(...)
            

            【讨论】:

              猜你喜欢
              • 2021-03-15
              • 2016-01-18
              • 1970-01-01
              • 2019-04-06
              • 1970-01-01
              • 1970-01-01
              • 2021-01-28
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多