NSURLConnection 返回错误而不是 401 的响应

NSURLConnection returning error instead of response for 401

我有一个 Web API,对于特定请求 returns 如果一切正常,状态代码为 200,如果用户未基于授权令牌登录,则状态代码为 401。如果响应状态为 200,则一切正常,但如果响应状态为 401,则似乎无法正常工作,返回代码为 -1012 的连接错误,而响应为 nil。

所以,下面的代码:

[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSLog(@"%@", response);
    NSLog(@"%@", connectionError);

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    int statusCode = (int)[httpResponse statusCode];
    NSLog(@"response status code: %d", statusCode);

会显示

2015-04-01 15:58:18.511 MyProject[3618:694604] <NSHTTPURLResponse: 0x155facc0> { URL: *SOME_URL* } { status code: 200, headers {
    "Access-Control-Allow-Headers" = "Content-Type, Accept, X-Requested-With";
    "Access-Control-Allow-Methods" = "POST, GET, PUT, UPDATE, OPTIONS";
    "Access-Control-Allow-Origin" = "*";
    Connection = "keep-alive";
    "Content-Type" = "application/json";
    Date = "Wed, 01 Apr 2015 12:58:14 GMT";
    Server = "Wildfly 8";
    "Transfer-Encoding" = Identity;
    "X-Powered-By" = "Undertow 1";
} }
2015-04-01 15:58:18.513 MyProject[3618:694604] (null)
2015-04-01 15:58:18.513 MyProject[3618:694604] response status code: 200

如果响应状态是200,而如果状态码是401,我会得到:

2015-04-01 16:05:55.988 MyProject[3633:695836] (null)
2015-04-01 16:05:55.992 MyProject[3633:695836] Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x146137c0 {NSErrorFailingURLKey=*SOME_URL*, NSErrorFailingURLStringKey=*SOME_URL*, NSUnderlyingError=0x1459e6d0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
2015-04-01 16:05:55.992 MyProject[3633:695836] response status code: 0

如果我使用 Postman 或 Android 设备执行相同的请求,我将获得状态代码 401,其中包含以下 headers(从 Postman 复制):

Connection → keep-alive
Content-Length → 30
Content-Type → application/json
Date → Wed, 01 Apr 2015 13:07:34 GMT
Server → Wildfly 8
X-Powered-By → Undertow 1

是否有任何修复程序或库可以给我一些准确的响应状态?我搜索了一些关于 -1012 错误的信息,但找不到太多,我真的不想以此为基础。

编辑:经过一些研究,我在 Appl 的文档中发现了以下声明:“如果需要身份验证才能下载请求,则必须将所需的凭据指定为 URL。如果身份验证失败,或凭据丢失,连接将尝试在没有凭据的情况下继续。"

但是我怎么知道这个错误是否会出现在 401 状态之后呢?它可以出现在其他类型的请求之后吗?

为了获得 401 状态代码,我认为您需要实施协议 NSURLConnectionDelegate 然后 connection:didReceiveAuthenticationChallenge: .

因此,您还需要通过委托,可能使用 [NSURLConnection connectionWithRequest:request delegate:self].

而且,如果您不尝试实施身份验证质询,我宁愿始终 return 200 状态代码,但具有不同的 json 内容。

希望对您有所帮助。

要检查401错误,你可以这样做:

if (error != nil && error.code == NSURLErrorUserCancelledAuthentication) {
    // do something for 401 error
}

希望对您有所帮助

I have a web API that, for a specific request returns status code 200 if everything went ok, and 401 if the user is not logged in based on an Authorization token. Everything works fine if the response status is 200, but doesn't seem to work properly if the response status is 401, returning a connection error with code -1012, while the response is nil.

我 运行 完全陷入同样的​​问题,REST API 在 Android 和 Postman 中调用 returns 401,但在 [=43= 中状态代码为 0 ] 出现连接错误,代码为 -1012。

您可以在 this SO post 中找到有关此问题的更多信息。

似乎是一个 iOS 错误(或者至少是非常奇怪的方法)同时发生在异步和同步请求中。

我 post 这样做是为了防止其他人遇到同样的问题。我在代码中所做的是在请求之后立即调用一个方法来检查每个托管的 http 状态代码来管理 401 状态。

方法接收(NSError **)error[(NSHTTPURLResponse *)response statusCode].

这是 401 部分 - 使用存储在 userInfo 结构中的错误详细信息。

// Auth failed or token problems
if (statusCode == 0 && [error userInfo] != nil) {

    // Get error detailed informations
    NSDictionary *userInfo = [error userInfo];
    NSString *errorString = [[userInfo objectForKey:NSUnderlyingErrorKey] localizedDescription];

    // If error message is of type authFailed or returns iOS code -1012 meaning auth failed
    if ([errorString containsString:@"kCFErrorDomainCFNetwork"] || [errorString containsString:@"-1012"]) {
        NSLog(@"%@ - ConnectionError - Code 401 - Cause: authentication failed, token is invalid or expired", type);
    } else {
        NSLog(@"%@ - ConnectionError - Cause: generic auth error", type);
    }

    // Alert user that auth failed
    ...
}

另一种方法是按照上面@ThuanDINH 的建议直接检查此错误代码 (-1012)。 (编辑了 objective c 的答案)。

我的代码可以改成:

// Auth failed - token problems
if (statusCode == 0 && [error code] == NSURLErrorUserCancelledAuthentication) {

    // If error code is UserCanceledAuthentication
    MPLog(MPLogLevelInfo, @"%@ - ConnectionError - Cause: authentication failed, token is invalid or expired", type);

    // Alert user that auth failed
    ...
}

但是用这种方式你不会处理所有其他错误(你需要打开每个 NSURLError 代码)。

Here 你可以找到包含所有 NSURLError 代码列表的 SO 问题。

基于 Apple 文档 https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html

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.

我们需要确保我们不会在代码中取消会话。例如,当 previousFailureCount > 1 时,我在 didReceiveChallenge 委托方法中调用 NSURLSessionAuthChallengeCancelAuthenticationChallenge。这会抑制 401 响应并调用 didReceiveResponse。

当我将上述值更改为 NSURLSessionAuthChallengePerformDefaultHandling 时,我在 didReceiveResponse 委托方法中收到 401 Unauthorized 响应并按预期工作。