Swift Alamofire: come ottenere il codice di stato della risposta HTTP


106

Vorrei recuperare il codice di stato della risposta HTTP (ad esempio 400, 401, 403, 503, ecc.) Per gli errori di richiesta (e idealmente anche per i successi). In questo codice, sto eseguendo l'autenticazione utente con HTTP di base e voglio essere in grado di inviare un messaggio all'utente che l'autenticazione non è riuscita quando l'utente digita erroneamente la password.

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

Sfortunatamente, l'errore prodotto non sembra indicare che sia stato effettivamente ricevuto un codice di stato 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

Inoltre, sarebbe bello recuperare il corpo HTTP quando si verifica un errore perché il mio lato server inserirà una descrizione testuale dell'errore lì.

Domande
È possibile recuperare il codice di stato su una risposta non 2xx?
È possibile recuperare il codice di stato specifico su una risposta 2xx?
È possibile recuperare il corpo HTTP su una risposta non 2xx?

Grazie!


1
Se non sei autenticato, ricevi un -999 per impostazione predefinita. Non sono sicuro del motivo o di come risolverlo ... Hai risolto questo problema?
Guido Hendriks

Risposte:


187

Per gli utenti di Swift 3.x / Swift 4.0 / Swift 5.0 con Alamofire> = 4.0 / Alamofire> = 5.0


response.response?.statusCode

Esempio più dettagliato:

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 contiene un sistema di errori completamente nuovo, guarda qui per i dettagli)

Per gli utenti di Swift 2.x con 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 può darti un errore di Alamofire, ad esempio. StatusCodeValidationFailed, FAILURE: Error Domain=com.alamofire.error Code=-6003. È se si desidera effettivamente ricevere un errore di risposta HTTP è meglio per l'utenteresponse.response?.statusCode
Kostiantyn Koval

@KostiantynKoval Sono d'accordo con te, hai fatto una debita precisazione. Ho aggiornato la mia risposta per chiarezza
Alessandro Ornano

50

Nel gestore di completamento con l'argomento responseseguente trovo che il codice di stato http sia in 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
                 }

Salve, statusCode 200 cadrà in errore? la mia richiesta è stata gestita correttamente sul lato server ma la risposta rientra in Fallimento
perwyl

1
@perwyl Non credo che 200 è un errore http: vedi stackoverflow.com/questions/27921537/...
wcochran

2
Il codice di stato 200 di @perwyl indica il successo, se il tuo server ha restituito 200 e la risposta indica un errore (cioè una proprietà chiamata issuccess = false), devi gestirlo nel tuo codice frontend
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):
    }

Questo stimola le migliori pratiche di API
CESCO

URW :) Prova ad implementare il Router per le tue richieste. ;)
Abo3atef

11

Il modo migliore per ottenere il codice di stato utilizzando alamofire.

 Alamofire.request (URL) .responseJSON {
  risposta in

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

}

5

Al responseJSONtermine, puoi ottenere il codice di stato dall'oggetto risposta, che ha un tipo di NSHTTPURLResponse?:

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

Ciò funzionerà indipendentemente dal fatto che il codice di stato si trovi nell'intervallo di errore. Per ulteriori informazioni, dai un'occhiata alla documentazione NSHTTPURLResponse .

Per la tua altra domanda, puoi utilizzare la responseStringfunzione per ottenere il corpo della risposta grezza. Puoi aggiungerlo in aggiunta a responseJSONe verranno chiamati entrambi.

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

3

Il tuo errore indica che l'operazione è stata annullata per qualche motivo. Avrei bisogno di maggiori dettagli per capire perché. Ma penso che il problema più grande potrebbe essere che dal momento che il tuo endpoint https://host.com/a/pathè fasullo, non esiste una risposta reale del server da segnalare, e quindi stai vedendo nil.

Se raggiungi un endpoint valido che fornisce una risposta adeguata, dovresti vedere un valore non nullo per res (usando le tecniche menzionate da Sam) sotto forma di un NSURLHTTPResponseoggetto con proprietà come statusCode, ecc.

Inoltre, per essere chiari, error è di tipo NSError. Ti dice perché la richiesta di rete non è riuscita. Il codice di stato dell'errore sul lato server è in realtà una parte della risposta.

Spero che questo aiuti a rispondere alla tua domanda principale.


Ottima presa, ero troppo concentrato sulla lista delle domande in fondo.
Sam

1
In realtà sta ricevendo un codice 401 Non autorizzato perché sto inviando intenzionalmente la password sbagliata per simulare un utente che digita erroneamente la propria password in modo che io possa rilevare quel caso e fornire un feedback all'utente. Quello non è l'URL effettivo che sto utilizzando, ma sto usando un URL legittimo che ha esito positivo quando invio la password corretta. L'output della console nel mio post originale è l'output effettivo del raggiungimento di un URL reale (tranne per il fatto che l'URL è falso) e puoi vedere che l' resoggetto lo è nil, quindi questa risposta non aiuta, mi dispiace.
GregT

Grazie per il chiarimento. Bene, allora l'unica cosa che sospetta qui è l'errore -999 che non ho riscontrato, ma la documentazione suggerisce che la richiesta è stata annullata (quindi la questione della ricezione di una risposta dovrebbe essere discutibile). Hai provato a stampare l'oggetto risposta per un diverso tipo di errore non correlato all'autenticazione? Solo curioso.
rainypixels

ahhhh pensavo errorsi riferisse a risposte con codici di stato fuori dall'intervallo che forniamo validate(). Grazie!!!
Gerald

3

Oppure usa il pattern matching

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

Ha funzionato come un fascino.
alasker

3

puoi controllare il seguente codice per il gestore del codice di stato di 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)
        }
    }

se il codice di stato non è convalidato, verrà inserito l'errore nel caso dell'interruttore


1

Per gli utenti di Swift 2.0 con Alamofire> 2.0

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

1

Avevo bisogno di sapere come ottenere il numero del codice di errore effettivo.

Ho ereditato un progetto da qualcun altro e ho dovuto ottenere i codici di errore da una .catchclausola che avevano precedentemente impostato per 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)
}

O se hai bisogno di ottenerlo dal responsevalore segui la risposta di @ 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)
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.