NSURLSessionDataTask 超时后续请求失败

NSURLSessionDataTask timeout subsequent requests failing

我正在创建 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];
}

我没看到你恢复你开始的任务。您需要申报:

[task resume];

此行恢复任务(如果暂停)。

尝试调用 NSURLSession 如下:

[NSURLSession sharedSessison] instead of self.session

并通过以下方式使会话无效:

 [[NSURLSession sharedSession]invalidateAndCancel];

来自 Apple 的文档:

When your app no longer needs a session, invalidate it by calling either invalidateAndCancel (to cancel outstanding tasks) or finishTasksAndInvalidate (to allow outstanding tasks to finish before invalidating the object).

    - (void)invalidateAndCancel

Once invalidated, references to the delegate and callback objects are broken. Session objects cannot be reused.

要允许未完成的任务 运行 直到完成,请改为调用 finishTasksAndInvalidate。

  - (void)finishTasksAndInvalidate

This method returns immediately without waiting for tasks to finish. Once a session is invalidated, new tasks cannot be created in the session, but existing tasks continue until completion. After the last task finishes and the session makes the last delegate call, references to the delegate and callback objects are broken. Session objects cannot be reused.

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

超时的最可能原因是 DNS 解析为不存在的 IP 地址,或者服务器已崩溃并需要重新启动。在任何情况下,如果一个请求因超时而失败,则更多请求也很可能因超时而失败。

您显然需要以这样一种方式编写您的应用程序,即它可以在服务器不回复时继续存在。

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

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

您在这里最有可能遇到的问题是您的任务没有取消或完成,因此阻止会话接受更多任务。根据 Apple 的文档

After you create a task, you start it by calling its resume method. The session then maintains a strong reference to the task until the request finishes or fails;

按照T_77的建议,尝试使用[NSURLSession sharedSession]

此时我还想尝试做的另一件事是尝试使用 Instruments

找出在会话对象和任务之间是否创建了一个保留周期

可能发生的另一件事是请求格式不正确并且未执行或挂起。当我尝试将 URL 加载到 Web 视图时,我曾经遇到过类似的问题。该页面未加载且未引发错误。也尝试验证 url 请求一次。

谢谢, 苏拉吉