NSURLSessionDataTask超时后,后续请求失败

11

我正在创建一个 NSMutableRequest

self.req = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];

超时时间设置为10秒,因为我不希望用户等待太久才能收到反馈。 随后我创建一个NSURLSessionDataTask

NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse * httpResp = (NSHTTPURLResponse *)response;
    if (error) {
        // this is where I get the timeout
    } 
    else if (httpResp.statusCode < 200 || httpResp.statusCode >= 300) {
        // handling error and giving feedback
    } 
    else {
        NSError *serializationError = nil;
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&serializationError];
    }
    [task resume];
}
问题是服务器进入网关超时状态,并且需要很长时间。我收到超时错误并向用户提供反馈,但所有后续API调用都因超时错误而失败。 唯一的解决方法是杀死应用程序并重新启动。 在超时错误后,是否有什么方法可以停止任务或连接? 如果我不设置超时并等待直到从服务器收到错误代码,那么所有后续调用都能正常工作(但用户需要等待很久!)。
我尝试取消任务:
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse * httpResp = (NSHTTPURLResponse *)response;
    if (error) {
        // this is where I get the timeout
        [task cancel];
    } 
    ...
    [task resume];
}

我猜,如果出现错误/超时,您可能需要重新初始化 self.req。不过我不太确定。 - Mrunal
尝试使用Chrome中的POSTMAN应用程序调用连接,看看是否仍然会出现超时错误。 - Teja Nandamuri
你是在某个块内创建这个任务吗?还是在主线程之外的其他线程中? - Mayur Deshmukh
@nicky 你能找出解决方案吗?我遇到了同样的情况。我得到了服务器超时错误,将所有请求排队并重试,但它总是失败。 - Shikha Shah
4个回答

5
我没有看到您重新开始之前未完成的任务。您需要声明:
[task resume];

如果任务已挂起,则此行恢复任务。

尝试按以下方式调用NSURLSession:

[NSURLSession sharedSessison] instead of self.session

通过以下方式使会话失效:

 [[NSURLSession sharedSession]invalidateAndCancel];

来自苹果文档:

当您的应用程序不再需要会话时,请通过调用invalidateAndCancel(以取消未完成的任务)或finishTasksAndInvalidate(在使对象无效之前允许未完成的任务完成)来使其失效。

    - (void)invalidateAndCancel

当Session对象失效后,对代理和回调对象的引用将被断开。Session对象不能再重复使用。

为了让未完成的任务运行直至完成,请调用finishTasksAndInvalidate方法。

  - (void)finishTasksAndInvalidate

该方法立即返回,而不等待任务完成。一旦会话失效,就不能在会话中创建新任务,但现有任务会继续直到完成。在最后一个任务完成并且会话进行了最后一个委托调用之后,对委托和回调对象的引用将被断开。会话对象无法重复使用。

要取消所有未完成的任务,请调用invalidateAndCancel。


是的,我在问题中忘记了简历。我将编辑它。我可以调用任务上的唯一无效方法是“cancel”。我的视野中没有其他方法。我尝试了,但它无法解决问题。谢谢 - nicky_1525
你是如何调用取消操作的? - Teja Nandamuri

1
你可能遇到的问题是你的任务没有被取消或完成,因此阻止了会话接受更多任务。根据苹果的文档:
当你创建一个任务后,通过调用它的 resume 方法来启动它。然后会话将保持对该任务的强引用,直到请求完成或失败为止。
正如 T_77 建议的那样,尝试使用 [NSURLSession sharedSession]。
此时,我还想尝试做的一件事是使用 Instruments 找出会话对象和任务之间是否创建了保留循环。
还有一件可能发生的事情是请求没有正确形成,没有执行或挂起。我曾经遇到过类似的问题,当我尝试将 URL 加载到 Web 视图上时,页面没有加载并且没有抛出错误。尝试验证一下 URL 请求。
谢谢, Suraj

0

超时的最可能原因是DNS解析到了一个不存在的IP地址,或者服务器已经崩溃需要重新启动。无论哪种情况,如果一个请求超时失败,更多的请求也很有可能会超时失败。

显然,您需要编写应用程序,使其能够在服务器不回复时保持运行。


如果我将超时时间设置为60秒而不是10秒,我会从服务器获得“网关超时”错误,之后我做的所有请求都能完美地工作。问题在于,当超时发生在服务器回应之前时,所有随后的请求都会失败,直到我关闭应用程序。 - nicky_1525

0

您可以像以下代码一样以不同的方式设置超时时间

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.timeoutIntervalForRequest = timeout;
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:nil delegateQueue:nil];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接