以下のリンクで説明されているのと同様の問題があります。
NSHTTPURLResponse statusCodeは、401である必要があるときにゼロを返します
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
を使用してサーバーからデータを取得します。
NSURLConnectionがHTTPコード401を受信すると、NSURLErrorDomainからコード-1012
のエラーオブジェクト以外は返されません。 -1012
はNSURLErrorUserCancelledAuthentication
に対応します。 HTTPヘッダーを解析する必要があるため、NSURLConnectionが作成したエラーではなく、元のエラーを取得する必要があります。
元の401httpパケットを受信する方法はありますか?
はい。同期APIの使用を停止します。非同期デリゲートベースのAPIを使用する場合は、接続をより細かく制御できます。このAPIでは、HTTPヘッダーを受信する前にエラーが発生した場合を除いて、常に受信-connection:didReceiveResponse:
、HTTPヘッダーフィールド(NSURLResponse
オブジェクトにカプセル化されている)へのアクセスを提供します。必要に応じて、関連するデリゲートメソッドを使用して認証を実装することもできます。
回避策:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue new] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSHTTPURLResponse *aResponse = (NSHTTPURLResponse *)response;
int statusCodeResponse = aResponse.statusCode;
NSString *strError = [NSString stringWithFormat:@"%@", [connectionError description]];
if ([strError rangeOfString:@"Code=-1012"].location != NSNotFound) {
statusCodeResponse = 401;
}
最善の解決策ではありませんが、機能します。
このスレッドに対する「推奨」の回答に驚いています。
非同期バージョンのメソッドを使用する方が良いと確信していますが、それでもsendSynchronousRequest
関数が許可する理由は説明されていません。変数を渡して応答コードを返しますが、状況によってはnilを返すだけです。
この問題が報告されてから4年、iOS8.2でXCode6.2を使用していますが、この古いバグはまだ存在しています。
私のWebサービスは、ユーザーのユーザー名とパスワードが正しくない場合、意図的に401エラーを返します。
私のiPhoneアプリが(間違った資格情報で)このサービスを呼び出すとき...
NSHTTPURLResponse *response = nil;
NSData *data = [ NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error ];
..response
はnilとして返されます(したがって、Ica n'ttest for the HTTP Response 401)、error
次のようにラップされた-1012メッセージを受信します。
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)"
UserInfo=0x174869940 {NSErrorFailingURLStringKey=https://mywebservice.com/Service1.svc/getGroupInfo/6079, NSUnderlyingError=0x174e46030
"The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)",
NSErrorFailingURLKey=https://mywebservice.com/Service1.svc/getGroupInfo/6079}
sendSynchronousRequest
関数は、...を含む長いXML文字列を返します...this.. ..
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Request Error</title>
<style>BODY { color: #000000; background-color: white; font-family: Verdana; margin-left: 0px; margin-top: 0px; } #content { margin-left: 30px; font-size: .70em; padding-bottom: 2em; } A:link { color: #336699; font-weight: bold; text-decoration: underline; } A:visited { color: #6699cc; font-weight: bold; text-decoration: underline; } A:active { color: #336699; font-weight: bold; text-decoration: underline; } .heading1 { background-color: #003366; border-bottom: #336699 6px solid; color: #ffffff; font-family: Tahoma; font-size: 26px; font-weight: normal;margin: 0em 0em 10px -20px; padding-bottom: 8px; padding-left: 30px;padding-top: 16px;} pre { font-size:small; background-color: #e5e5cc; padding: 5px; font-family: Courier New; margin-top: 0px; border: 1px #f0f0e0 solid; white-space: pre-wrap; white-space: -pre-wrap; Word-wrap: break-Word; } table { border-collapse: collapse; border-spacing: 0px; font-family: Verdana;} table th { border-right: 2px white solid; border-bottom: 2px white solid; font-weight: bold; background-color: #cecf9c;} table td { border-right: 2px white solid; border-bottom: 2px white solid; background-color: #e5e5cc;}</style>
</head>
<body>
<div id="content">
<p class="heading1">Request Error</p>
<p>The server encountered an error processing the request. The exception message is 'Access is denied.'. See server logs for more details. The exception stack trace is: </p>
<p> at System.ServiceModel.Dispatcher.AuthorizationBehavior.Authorize(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</p>
</div>
</body>
</html>
Appleに来て、バグを修正してください...
私は401Unauthorizedエラーコードを受け取らないという問題に直面していました(nil応答を受け取り、didReceiveResponseメソッドが呼び出されませんでした)代わりに-999キャンセルエラーを受け取りました。私がコードで行っていた間違いは次のとおりです。didReceiveChallenge:デリゲートメソッドでは、
if (challenge.previousFailureCount == 0)
{
//handle certificate trust
completionHandler (NSURLSessionAuthChallengeUseCredential, newCredential);
}
else
{
completionHandler (NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
NSURLSessionAuthChallengeCancelAuthenticationChallengeの結果は-999エラーになり、401応答は取得されませんでした。代わりに、completionHandler(NSURLSessionAuthChallengePerformDefaultHandling、nil)を使用した場合。期待どおり、didReceiveResponse:デリゲートメソッドで401応答を受信していました。
IOSドキュメントからのメモ https://developer.Apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html 、urlsessionをキャンセルすると、次のように報告されます。キャンセルされましたが、応答の401エラーとしてではありません。
Note: NSURLSession does not report server errors through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the Host. The error codes are described in URL Loading System Error Codes.
Server-side errors are reported through the HTTP status code in the NSHTTPURLResponse object. For more information, read the documentation for the NSHTTPURLResponse and NSURLResponse classes.
その実際には単純に終了します。さて、非同期リクエストが実際にはかなり良いヘルパーであることは事実です。しかし、それは単なるヘルパーであることを覚えておく必要があります。 Httpはネットワーク用の単なるプロトコルであるため、ユーザーと対話してはなりません。言い換えれば、両方のケースは実際には同じです。
非同期ヘルパーを使用したくない場合は、ユーザーにログインダイアログを表示し、ユーザーがキャンセルを押すまでリクエストを繰り返すことをお勧めします。
[編集]
情報のためだけに、個人的にはカールが好きです。ほとんどどこでも魅力のように機能します;)