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

时间:2022-10-08 23:59:14

I would like to retrieve the HTTP response status code (e.g. 400, 401, 403, 503, etc) for request failures (and ideally for successes too). In this code, I am performing user authentication with HTTP Basic and want to be able to message the user that authentication failed when the user mistypes their password.

我想要检索请求失败的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")
}

Unfortunately, the error produced does not seem to indicate that an HTTP status code 409 was actually received:

不幸的是,产生的错误似乎并不表明实际收到了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

Additionally, it would be nice to retrieve the HTTP body when an error occurs because my server-side will put a textual description of the error there.

此外,当出现错误时,检索HTTP主体是很好的,因为我的服务器端将对错误进行文本描述。

Questions
Is it possible to retrieve the status code upon a non-2xx response?
Is it possible to retrieve the specific status code upon a 2xx response?
Is it possible to retrieve the HTTP body upon a non-2xx response?

是否有可能在非2xx响应时检索状态码?是否可以在2xx响应上检索特定的状态代码?是否可以在非2xx响应上检索HTTP主体?

Thanks!

谢谢!

9 个解决方案

#1


132  

For Swift 3.x / Swift 4.0 users with Alamofire >= 4.0

斯威夫特3。使用Alamofire >= 4.0的用户

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..
                }

                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 contains a completely new error system, look here for details)

(Alamofire 4包含了一个全新的错误系统,详情请参见这里)

For Swift 2.x users with Alamofire >= 3.0

为迅速2。使用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
             }
}

#2


39  

In the completion handler with argument response below I find the http status code is in response.response.statusCode:

在后面带有参数响应的完成处理程序中,我发现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
                 }

#3


15  

    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):
    }

#4


4  

In your responseJSON completion, you can get the status code from the response object, which has a type of NSHTTPURLResponse?:

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

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

This will work regardless of whether the status code is in the error range. For more information, take a look at the NSHTTPURLResponse documentation.

不管状态代码是否在错误范围内,这都可以工作。有关更多信息,请参阅NSHTTPURLResponse文档。

For your other question, you can use the responseString function to get the raw response body. You can add this in addition to responseJSON and both will be called.

对于您的另一个问题,您可以使用responseString函数来获取原始响应体。除了responseJSON之外,您还可以添加这个,这两个都将被调用。

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

#5


3  

Your error indicates that the operation is being cancelled for some reason. I'd need more details to understand why. But I think the bigger issue may be that since your endpoint https://host.com/a/path is bogus, there is no real server response to report, and hence you're seeing nil.

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

If you hit up a valid endpoint that serves up a proper response, you should see a non-nil value for res (using the techniques Sam mentions) in the form of a NSURLHTTPResponse object with properties like statusCode, etc.

如果您找到一个提供适当响应的有效端点,您应该会看到一个非nil的res值(使用Sam提到的技术),其形式是NSURLHTTPResponse对象,具有statusCode等属性。

Also, just to be clear, error is of type NSError. It tells you why the network request failed. The status code of the failure on the server side is actually a part of the response.

另外,需要明确的是,error类型为NSError。它告诉您为什么网络请求失败。服务器端失败的状态代码实际上是响应的一部分。

Hope that helps answer your main question.

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

#6


3  

Best way to get the status code using alamofire.

 Alamofire.request(URL).responseJSON {
  response in

  let status = response.response?.statusCode
  print("STATUS \(status)")

}

#7


2  

Or use pattern matching

或者使用模式匹配

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

#8


1  

For Swift 2.0 users with Alamofire > 2.0

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

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

#9


1  

you may check the following code for status code handler by alamofire

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

if status code is not validate it will be enter the failure in switch case

如果状态码没有被验证,它将在开关情况下输入失败

#1


132  

For Swift 3.x / Swift 4.0 users with Alamofire >= 4.0

斯威夫特3。使用Alamofire >= 4.0的用户

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..
                }

                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 contains a completely new error system, look here for details)

(Alamofire 4包含了一个全新的错误系统,详情请参见这里)

For Swift 2.x users with Alamofire >= 3.0

为迅速2。使用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
             }
}

#2


39  

In the completion handler with argument response below I find the http status code is in response.response.statusCode:

在后面带有参数响应的完成处理程序中,我发现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
                 }

#3


15  

    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):
    }

#4


4  

In your responseJSON completion, you can get the status code from the response object, which has a type of NSHTTPURLResponse?:

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

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

This will work regardless of whether the status code is in the error range. For more information, take a look at the NSHTTPURLResponse documentation.

不管状态代码是否在错误范围内,这都可以工作。有关更多信息,请参阅NSHTTPURLResponse文档。

For your other question, you can use the responseString function to get the raw response body. You can add this in addition to responseJSON and both will be called.

对于您的另一个问题,您可以使用responseString函数来获取原始响应体。除了responseJSON之外,您还可以添加这个,这两个都将被调用。

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

#5


3  

Your error indicates that the operation is being cancelled for some reason. I'd need more details to understand why. But I think the bigger issue may be that since your endpoint https://host.com/a/path is bogus, there is no real server response to report, and hence you're seeing nil.

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

If you hit up a valid endpoint that serves up a proper response, you should see a non-nil value for res (using the techniques Sam mentions) in the form of a NSURLHTTPResponse object with properties like statusCode, etc.

如果您找到一个提供适当响应的有效端点,您应该会看到一个非nil的res值(使用Sam提到的技术),其形式是NSURLHTTPResponse对象,具有statusCode等属性。

Also, just to be clear, error is of type NSError. It tells you why the network request failed. The status code of the failure on the server side is actually a part of the response.

另外,需要明确的是,error类型为NSError。它告诉您为什么网络请求失败。服务器端失败的状态代码实际上是响应的一部分。

Hope that helps answer your main question.

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

#6


3  

Best way to get the status code using alamofire.

 Alamofire.request(URL).responseJSON {
  response in

  let status = response.response?.statusCode
  print("STATUS \(status)")

}

#7


2  

Or use pattern matching

或者使用模式匹配

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

#8


1  

For Swift 2.0 users with Alamofire > 2.0

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

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

#9


1  

you may check the following code for status code handler by alamofire

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

if status code is not validate it will be enter the failure in switch case

如果状态码没有被验证,它将在开关情况下输入失败