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?
Можно ли получить тело HTTP при ответе, отличном от 2xx?

Спасибо!


1
Если вы не прошли аутентификацию, вы получите -999. Не уверен, почему это так и как это можно решить ... Вы это решили?
Гвидо Хендрикс

Ответы:


188

Для пользователей 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 содержит совершенно новую систему ошибок, подробности смотрите здесь )

Для пользователей 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. StatusCodeValidationFailed, FAILURE: Error Domain=com.alamofire.error Code=-6003. Если вы действительно хотите получить ошибку HTTP-ответа, лучше для пользователяresponse.response?.statusCode
Константин Коваль

@KostiantynKoval Я согласен с вами, вы сделали правильное разъяснение. Я обновил свой ответ для ясности
Алессандро Орнано

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 сбой? мой запрос был обработан правильно на стороне сервера, но ответ попадает в категорию Failure
perwyl

1
@perwyl Я не думаю, что 200 - это ошибка http: см. stackoverflow.com/questions/27921537/…
wcochran

2
Код состояния @perwyl 200 указывает на успех, если ваш сервер вернул 200 и ответ, указывающий на ошибку (то есть какое-то свойство с именем Issueccess = false), вы должны обработать это в своем коде
внешнего

17
    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 {
  ответ в

  let status = response.response? .statusCode
  print ("СТАТУС \ (статус)")

}

4

По 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.

Если вы обнаружите допустимую конечную точку, которая обеспечивает правильный ответ, вы должны увидеть ненулевое значение для res(с использованием методов, упомянутых Сэмом) в форме NSURLHTTPResponseобъекта со свойствами, такими как statusCodeи т. Д.

Кроме того, для ясности, errorотносится к типу NSError. Он сообщает вам, почему сетевой запрос не удался. Код состояния сбоя на стороне сервера фактически является частью ответа.

Надеюсь, это поможет ответить на ваш главный вопрос.


Хороший улов, я был слишком сосредоточен на списке вопросов внизу.
Сэм,

1
Фактически он получает код 401 Unauthorized, потому что я намеренно отправляю неправильный пароль, чтобы имитировать неправильный ввод пароля пользователем, чтобы я мог поймать этот случай и дать отзыв пользователю. Это не фактический URL-адрес, который я использую, но я использую законный URL-адрес, который приводит к успеху, когда я отправляю правильный пароль. Вывод консоли в моем исходном сообщении является фактическим результатом попадания в реальный URL-адрес (за исключением того, что URL-адрес поддельный), и вы можете видеть, что resобъект есть nil, поэтому этот ответ не помогает, извините.
GregT

Спасибо за разъяснение. Что ж, тогда единственное, что здесь вызывает подозрение, - это ошибка -999, с которой я не сталкивался, но документация предполагает, что запрос отменяется (поэтому вопрос даже о получении ответа должен быть спорным). Вы пытались распечатать объект ответа для другого типа ошибки, не связанной с аутентификацией? Просто любопытно.
rainypixels

Ааааа я думал , что 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

Для пользователей Swift 2.0 с Alamofire> 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)
})
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.