Swift Alamofire:如何获取HTTP响应状态代码


106

我想检索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正文?

谢谢!


1
如果您未经身份验证,则会收到-999(按设计)。不知道为什么会这样或如何解决...您解决了吗?
Guido Hendriks

Answers:


187

对于Alamofire> = 4.0 / Alamofire> = 5.0的Swift 3.x / Swift 4.0 / Swift 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包含一个全新的错误系统,请点击此处查看详细信息)

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

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
Kostiantyn科瓦尔

@KostiantynKoval我同意你的意见,你已经做了适当的澄清。为了清楚起见,我更新了答案
Alessandro Ornano

50

在带有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

1
@perwyl我不认为200是一个HTTP错误:请参阅stackoverflow.com/questions/27921537/…–
wcochran

2
@perwyl状态码200表示成功,如果您的服务器返回200,并且响应表示错误(即,称为issuccess = false的某些属性),则您必须在前端代码中进行处理
Parama Dharmika

16
    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的最佳实践
CESCO

URW :)尝试为您的请求实现路由器。;)
Abo3atef

11

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

 Alamofire.request(URL).responseJSON {
  回应

  让状态= response.response?.statusCode
  print(“状态\(状态)”)

}

5

在你responseJSON完成,你可以从响应对象,其中有一个类型的状态代码NSHTTPURLResponse?

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

无论状态码是否在错误范围内,这都将起作用。有关更多信息,请参阅NSHTTPURLResponse文档

对于其他问题,您可以使用responseString函数获取原始响应正文。您可以添加它,responseJSON然后两者都将被调用。

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

3

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

如果您击中了一个可以提供适当响应的有效端点,则应该以具有诸如等属性resNSURLHTTPResponse对象的形式(使用Sam提到的技术)看到非零值statusCode

另外,请注意,error类型是NSError。它告诉您网络请求失败的原因。服务器端故障的状态代码实际上是响应的一部分。

希望能帮助您回答主要问题。


很好,我太关注底部的问题列表了。
山姆

1
它实际上收到的代码是401未经授权,因为我故意发送了错误的密码来模拟用户输入错误的密码,这样我就可以发现这种情况并向用户提供反馈。那不是我使用的实际URL,但是我使用的合法URL在发送正确的密码后会成功。我原始帖子中的控制台输出是命中一个真实URL的实际输出(除了URL是伪造的),您可以看到该res对象是nil,所以抱歉,此答案无济于事。
GregT

感谢您的澄清。好吧,那么这里唯一令人怀疑的是我没有遇到过的-999错误,但是文档表明请求已被取消(因此,即使收到响应也应解决)。您是否尝试针对与身份验证无关的其他类型的错误打印响应对象?只是好奇。
rainypixels 2015年

ahhhh我以为error是指状态代码超出我们提供的范围的响应validate()。谢谢!!!
杰拉尔德

3

或使用模式匹配

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

像魅力一样工作。
alasker

3

您可以通过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)
        }
    }

如果状态代码无效,则在切换情况下将输入失败


1

对于Alamofire> 2.0的Swift 2.0用户

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

1

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

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

} .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的回答

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)
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.