Swift Alamofire: So erhalten Sie den HTTP-Antwortstatuscode

106

Ich möchte den HTTP-Antwortstatuscode (z. B. 400, 401, 403, 503 usw.) für Anforderungsfehler (und idealerweise auch für Erfolge) abrufen. In diesem Code führe ich eine Benutzerauthentifizierung mit HTTP Basic durch und möchte dem Benutzer mitteilen können, dass die Authentifizierung fehlgeschlagen ist, wenn der Benutzer sein Kennwort falsch eingibt.

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

Leider scheint der erzeugte Fehler nicht darauf hinzudeuten, dass tatsächlich ein HTTP-Statuscode 409 empfangen wurde:

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

Außerdem wäre es schön, den HTTP-Body abzurufen, wenn ein Fehler auftritt, da meine Serverseite dort eine Textbeschreibung des Fehlers einfügt.

Fragen
Ist es möglich, den Statuscode bei einer Nicht-2xx-Antwort abzurufen?
Ist es möglich, den spezifischen Statuscode bei einer 2xx-Antwort abzurufen?
Ist es möglich, den HTTP-Body bei einer Nicht-2xx-Antwort abzurufen?

Vielen Dank!

GregT
quelle
1
Wenn Sie nicht authentifiziert sind, erhalten Sie per Design eine -999. Nicht sicher, warum dies so ist oder wie es gelöst werden kann ... Haben Sie das gelöst?
Guido Hendriks

Antworten:

187

Für Swift 3.x / Swift 4.0 / Swift 5.0- Benutzer mit Alamofire> = 4.0 / Alamofire> = 5.0


response.response?.statusCode

Ausführlicheres Beispiel:

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 enthält ein völlig neues Fehlersystem, sucht hier für weitere Details)

Für Swift 2.x- Benutzer mit 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
             }
}
Alessandro Ornano
quelle
response.result.error kann beispielsweise einen Alamofire-Fehler verursachen. StatusCodeValidationFailed, FAILURE: Error Domain=com.alamofire.error Code=-6003. Es ist, wenn Sie tatsächlich HTTP-Antwortfehler erhalten möchten, ist es besser für Benutzerresponse.response?.statusCode
Kostiantyn Koval
@KostiantynKoval Ich stimme Ihnen zu, Sie haben eine ordnungsgemäße Klarstellung vorgenommen. Ich habe meine Antwort aus Gründen der Klarheit aktualisiert
Alessandro Ornano
50

Im Vervollständigungshandler mit dem folgenden Argument responsefinde ich den http-Statuscode 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
                 }
wcochran
quelle
Hallo, fällt der statusCode 200 aus? Meine Anfrage wurde auf der Serverseite korrekt behandelt, aber die Antwort fällt unter Failure
perwyl
1
@perwyl Ich glaube nicht, dass 200 ein http-Fehler ist: siehe stackoverflow.com/questions/27921537/…
wcochran
2
@perwyl Statuscode 200 zeigt Erfolg an, wenn Ihr Server 200 zurückgegeben hat und die Antwort Fehler anzeigt (dh eine Eigenschaft namens issuccess = false), müssen Sie dies in Ihrem Frontend-Code behandeln
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):
    }
Abo3atef
quelle
Dies stimuliert die Best Practices von API
CESCO
URW :) Versuchen Sie, Router für Ihre Anforderungen zu implementieren. ;)
Abo3atef
11

Der beste Weg, um den Statuscode mit alamofire zu erhalten.

 Alamofire.request (URL) .responseJSON {
  Antwort in

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

}}
Jamesdelacruz
quelle
5

Nach responseJSONAbschluss können Sie den Statuscode vom Antwortobjekt abrufen, das Folgendes aufweist NSHTTPURLResponse?:

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

Dies funktioniert unabhängig davon, ob der Statuscode im Fehlerbereich liegt. Weitere Informationen finden Sie in der Dokumentation zu NSHTTPURLResponse .

Für Ihre andere Frage können Sie die responseStringFunktion verwenden, um den rohen Antworttext abzurufen. Sie können dies zusätzlich hinzufügen responseJSONund beide werden aufgerufen.

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

Ihr Fehler zeigt an, dass der Vorgang aus irgendeinem Grund abgebrochen wird. Ich brauche mehr Details, um zu verstehen, warum. Aber ich denke, das größere Problem könnte sein, dass https://host.com/a/pathes keine echte Serverantwort gibt, die gemeldet werden muss, da Ihr Endpunkt gefälscht ist, und daher sehen Sie nil.

Wenn Sie einen gültigen Endpunkt finden, der eine ordnungsgemäße Antwort liefert, sollten Sie einen Wert ungleich Null res(unter Verwendung der von Sam erwähnten Techniken) in Form eines NSURLHTTPResponseObjekts mit Eigenschaften wie statusCodeusw. sehen.

Auch um klar zu sein, errorist von Typ NSError. Hier erfahren Sie, warum die Netzwerkanforderung fehlgeschlagen ist. Der Statuscode des Fehlers auf der Serverseite ist tatsächlich Teil der Antwort.

Ich hoffe, das hilft bei der Beantwortung Ihrer Hauptfrage.

Regenpixel
quelle
Guter Fang, ich habe mich zu sehr auf die Liste der Fragen unten konzentriert.
Sam
1
Es wird tatsächlich ein Code 401 Unauthorized empfangen, da ich absichtlich das falsche Passwort sende, um zu simulieren, dass ein Benutzer sein Passwort falsch eingibt, damit ich diesen Fall abfangen und dem Benutzer Feedback geben kann. Das ist nicht die tatsächliche URL, die ich verwende, aber ich verwende eine legitime URL, die zum Erfolg führt, wenn ich das richtige Passwort sende. Die Konsolenausgabe in meinem ursprünglichen Beitrag ist die tatsächliche Ausgabe beim Aufrufen einer echten URL (außer dass die URL gefälscht ist), und Sie können sehen, dass es sich um ein resObjekt handelt nil. Diese Antwort hilft also leider nicht weiter.
GregT
Danke fürs klarstellen. Nun, das einzige, was hier verdächtig ist, ist der Fehler -999, auf den ich nicht gestoßen bin, aber die Dokumentation legt nahe, dass die Anfrage storniert wird (daher sollte die Frage, ob ich überhaupt eine Antwort erhalten soll, strittig sein). Haben Sie versucht, das Antwortobjekt für einen anderen Fehlertyp zu drucken, der nicht mit der Authentifizierung zusammenhängt? Nur neugierig.
Regenpixel
ahhhh ich dachte, ich errorbeziehe mich auf Antworten mit Statuscodes, die außerhalb des von uns angegebenen Bereichs liegen validate(). Vielen Dank!!!
Gerald
3

Oder verwenden Sie Pattern Matching

if let error = response.result.error as? AFError {
   if case .responseValidationFailed(.unacceptableStatusCode(let code)) = error {
       print(code)
   }
}
mbryzinski
quelle
Lief wie am Schnürchen.
Alasker
3

Sie können den folgenden Code für den Statuscode-Handler von alamofire überprüfen

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

Wenn der Statuscode nicht validiert ist, wird der Fehler im Schalterfall eingegeben

Amr wütend
quelle
1

Für Swift 2.0-Benutzer mit Alamofire> 2.0

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

Ich musste wissen, wie ich die tatsächliche Fehlercode-Nummer erhalten konnte.

Ich habe ein Projekt von jemand anderem geerbt und musste die Fehlercodes aus einer .catchKlausel abrufen, die sie zuvor für Alamofire eingerichtet hatten:

} .catch { (error) in

    guard let error = error as? AFError else { return }
    guard let statusCode = error.responseCode else { return }

    print("Alamofire statusCode num is: ", statusCode)
}

Oder wenn Sie es aus dem responseWert erhalten müssen, folgen Sie der Antwort von @ 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)
})
Lance Samaria
quelle