【问题标题】:NSURLConnection returning error instead of response for 401NSURLConnection 返回错误而不是响应 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 状态之后呢?可以在其他类型的请求之后出现吗?

【问题讨论】:

    标签: objective-c nsurlconnection nsurlrequest


    【解决方案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 响应并按预期工作。

        【讨论】:

          猜你喜欢
          • 2017-06-09
          • 1970-01-01
          • 2013-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-16
          • 1970-01-01
          • 2019-10-07
          相关资源
          最近更新 更多