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応答で特定のステータスコードを取得することは可能ですか?
2xx以外の応答でHTTP本文を取得することは可能ですか?

ありがとう!


1
認証されていない場合は、意図的に-999を受け取ります。これがなぜであるか、またはどのように解決できるのかわからない...これを解決しましたか?
グイドヘンドリックス

回答:


187

スイフト3.xの / スイフト4.0 / スイフト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には完全に新しいエラーシステムが含まれています。詳細はこちらをご覧ください)

Alamofire> = 3.0のSwift 2.xユーザーの場合

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エラーを発生させる可能性があります。StatusCodeValidationFailedFAILURE: Error Domain=com.alamofire.error Code=-6003。実際にHTTP応答エラーを取得したい場合は、ユーザーにとって優れていますresponse.response?.statusCode
Kostiantyn Koval

@KostiantynKoval私はあなたに同意します、あなたは適切な説明をしました。私は明確にするために私の回答を更新しました
Alessandro Ornano 2016

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は失敗しますか?私の要求はサーバー側で正しく処理されましたが、応答は失敗に該当します
perwyl

1
@perwyl 200はhttpエラーとは思わない:stackoverflow.com/questions/27921537/…を
wcochran

2
@perwylステータスコード200は成功を示し、サーバーが200を返し、応答がエラーを示す場合(つまり、issuccess = falseと呼ばれるプロパティ)、フロントエンドコードでそれを処理する必要があります
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):
    }

これは、APIのベストプラクティスを刺激します
CESCO

URW :)リクエストにルーターを実装してみてください。;)
Abo3atef 2016年

11

alamofireを使用してステータスコードを取得する最良の方法。

 Alamofire.request(URL).responseJSON {
  での対応

  let status = response.response?.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ようなプロパティを持つオブジェクトの形式で(Samが言及している手法を使用して)の非nil値が表示されますstatusCode

また、明確にするためにerror、タイプNSErrorです。ネットワーク要求が失敗した理由がわかります。サーバー側の障害のステータスコードは、実際には応答の一部です。

あなたの主な質問への回答に役立つことを願っています。


良いキャッチ、私は一番下の質問のリストに集中しすぎていました。
Sam

1
実際にコード401 Unauthorizedを受け取っているのは、意図的に間違ったパスワードを送信して、ユーザーがパスワードを誤って入力した場合をシミュレートして、そのケースをキャッチし、ユーザーにフィードバックできるようにするためです。それは実際に使用しているURLではありませんが、正しいパスワードを送信すると成功する正当なURLを使用しています。私の元の投稿のコンソール出力は、実際のURL(URLが偽物であることを除く)をヒットした実際の出力であり、resオブジェクトがnilであることを確認できるため、この回答は役に立ちません。
GregT 2015年

明確にしていただきありがとうございます。さて、ここで疑わしいのは、私が遭遇したことのない-999エラーだけですが、ドキュメントでは、要求がキャンセルされていることを示しています(そのため、応答を受信することについての質問は愚かであるはずです)。認証に関連しない別のタイプのエラーの応答オブジェクトを印刷しようとしましたか?ちょっと興味があるんだけど。
rainypixels 2015年

ああ、私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

Alamofire> 2.0のSwift 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)
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.