NSURLConnection 返回错误而不是响应 401
Posted
技术标签:
【中文标题】NSURLConnection 返回错误而不是响应 401【英文标题】:NSURLConnection returning error instead of response for 401 【发布时间】:2015-04-01 13:17:30 【问题描述】:我有一个 Web API,对于特定请求,如果一切正常,则返回状态代码 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(从 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 状态之后呢?可以在其他类型的请求之后出现吗?
【问题讨论】:
【参考方案1】:要检查 401 错误,您可以这样做:
if (error != nil && error.code == NSURLErrorUserCancelledAuthentication)
// do something for 401 error
希望对你有所帮助
【讨论】:
【参考方案2】:为了获得 401 状态码,我认为您需要实现协议 NSURLConnectionDelegate
,然后是 connection:didReceiveAuthenticationChallenge:
。
因此,您还需要传递委托,可能使用 [NSURLConnection connectionWithRequest:request delegate:self]
。
而且,如果您不尝试实施身份验证质询,我宁愿始终返回 200 状态码,但 json 内容不同。
希望对你有帮助。
【讨论】:
如我所见,connection:didReceiveAuthenticationChallenge: 已被 os.x 弃用(未来可能也适用于 ios),我认为 connection:willSendRequestForAuthenticationChallenge: 也会对我有所帮助,对吗?那我从哪里得到回复呢? 我猜会得到连接的响应:didReceiveResponse:。 您可以使用connection:didReceiveResponse、connection:didReceiveData和connectionDidFinishLoading。所以,你还需要实现 NSURLConnectionDataDelegate 协议。 您是否碰巧知道代码为-1012 的connectionError 是否特定于这个东西?无论如何,可以通过其他方式得到错误吗?现在将错误视为 401 响应会容易得多,因为我有很多不同的请求。不幸的是,现在无法将来自服务器的所有响应标记为 200。 不幸的是,我认为这是设计使然 :(。我想我已经看到在 c# 上发生了相同的行为,您需要在其中强制转换异常然后获得响应。【参考方案3】:我有一个 Web API,对于特定请求返回状态代码 200 如果一切正常,如果用户未登录,则为 401 授权令牌。如果响应状态一切正常 是 200,但如果响应状态为 401,返回代码-1012的连接错误,而响应 是零。
我遇到了完全相同的问题,REST API 调用在 Android 和 Postman 中返回 401,但在 iOS 中状态代码为 0,连接错误代码为 -1012。
您可以在this SO 帖子中找到有关此问题的更多信息。
似乎是异步和同步请求都发生的 iOS 错误(或至少是非常奇怪的方法)。
我发布此内容以防万一这可能对遇到相同问题的其他人有用。在请求之后,我在代码中管理 401 状态的方法是调用一个方法来检查每个托管的 http 状态代码。
方法接收(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)。 (编辑目标 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 问题。
【讨论】:
【参考方案4】:基于苹果文档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 响应并按预期工作。
【讨论】:
以上是关于NSURLConnection 返回错误而不是响应 401的主要内容,如果未能解决你的问题,请参考以下文章
NSURLConnection 即使在重置授权标头后也会返回缓存的响应
NSURLConnection 发送 GET 请求而不是 POST 请求
AFNetworking 在 NSError 对象中返回响应