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

На жаль, видана помилка не вказує на те, що код статусу 409 HTTP був дійсно отриманий:

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 за задумом. Не впевнений, чому це так чи як це можна вирішити ... Ви вирішили це?
Гвідо Хендрікс

Відповіді:


187

Для користувачів 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 потрапить під збій? мій запит був оброблений правильно на стороні сервера, але відповідь підпадає під
збій

1
@perwyl Я не думаю , що 200 помилка HTTP: см stackoverflow.com/questions/27921537 / ...
wcochran

2
@perwyl код статусу 200 вказує на успіх, якщо ваш сервер повернув 200 і відповідь, що вказує на помилку (тобто якесь властивість називається issueccess = false), то вам доведеться це
впорядкувати

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 {
  відповідь в

  нехай статус = відповідь.відповідь? .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.

Якщо ви виявите дійсну кінцеву точку, яка слугує належною відповіддю, вам слід побачити значення, що не має значення нульового значення res(використовуючи методики, про які згадує Сем) у вигляді NSURLHTTPResponseоб'єкта із властивостями на зразокstatusCode тощо

Крім того, просто, щоб бути зрозумілим, errorмає тип NSError. Він говорить вам, чому запит мережі не вдався. Код стану відмови на стороні сервера насправді є частиною відповіді.

Сподіваємось, що допоможе відповісти на ваше головне питання.


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

1
Насправді він отримує код 401 Несанкціонований, оскільки я навмисно надсилаю неправильний пароль, щоб імітувати користувача, помилково вводячи його пароль, щоб я міг зрозуміти цей випадок і надати відгуки користувача. Це не фактична URL-адреса, яку я використовую, але я використовую законну URL-адресу, яка приносить успіх, коли я надсилаю правильний пароль. Вихід з консолі в моєму початковому дописі - це фактичний вихід із попадання на реальну URL-адресу (за винятком того, що URL-адреса підроблена), і ви можете бачити, що resоб’єкт є nil, тому ця відповідь не допомагає, вибачте.
GregT

Дякуємо за уточнення. Ну, тоді єдине, що тут підозрює, - помилка -999, з якою я не стикався, але документація свідчить про те, що запит скасовується (тому питання навіть про отримання відповіді має бути суперечливим). Ви намагалися надрукувати об’єкт відповіді для іншого типу помилок, які не пов’язані з автором? Просто цікаво.
дощові пікселі

А-а-а-а, я думав, errorмається на увазі відповіді з кодами статусу, які виходять за рамки, які ми надаємо validate(). Дякую!!!
Джеральд

3

Або використовувати відповідність шаблону

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

Працював як шарм.
тупик

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.