【问题标题】:Incomplete file downloads using ASIHTTPRequest and Rackspace Cloud Files使用 ASIHTTPRequest 和 Rackspace Cloud Files 下载不完整的文件
【发布时间】:2012-03-05 05:27:23
【问题描述】:

我正在从 Rackspace 云文件下载 mp3 文件,对于大文件,我遇到了下载已成功完成但文件尚未完全下载的问题。例如,40 MB mp3 文件 (01:00:00 duration) 以 4.5 MB mp3 文件 (00:10:30 duration) 的形式下载。这不会一直发生。

  1. 关于发生了什么的任何指针?
  2. 为什么会发生这种情况,我该如何解决这个问题?
  3. 如何构建一个简单的校验和逻辑来检查文件是否已完全下载?

以下是我创建和发送异步请求的方式:

ASIHTTPRequest *request;
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setShouldAttemptPersistentConnection:NO]; 
[request setAllowResumeForFileDownloads:YES];
[request setDownloadProgressDelegate:self];
[request setShouldContinueWhenAppEntersBackground:YES];
[request setUserInfo:userInfo];
[request setDownloadDestinationPath:downloadPath];
[request setTemporaryFileDownloadPath:[NSString stringWithFormat:@"%@.download", downloadPath]];

[self.networkQueue addOperation:request];
[self.networkQueue go];

请注意,我正在使用具有 4 个并发下载的网络队列。

谢谢。

编辑(2012 年 3 月 5 日星期一下午 3:25)

因此,进一步调查显示ASINetworkQueue 正在调用requestDidFinishSelector 委托方法而不是requestDidFailSelectorASIHTTPRequest 对象返回的状态码是requestDidFinishSelector 方法中的206, HTTP/1.1 206 Partial Content。状态码应该是200, HTTP/1.1 200 OK

我还是不知道为什么!我仍然不知道如何解决这个问题。看来我必须删除部分下载的文件并重新开始下载过程。此时临时文件即%@.download被删除,这个部分下载的文件被放在目标路径。

【问题讨论】:

  • 你检查过是不是ASIHTTP的bug吗?
  • 是的,找不到类似的东西。
  • 嗨@Mustafa,我是刚将 rackspace 云服务与 iOS 集成的新手,如果你能指出可以引导我使用 iOS 连接到 rackspace 的资源,我会很高兴。有没有图书馆或SDK?
  • @bizsytes 您实际上不需要任何库或 SDK 即可在您的 iOS 应用程序中使用 rackspace 云服务器。将文件上传到云端后,只需致电(例如)stringWithContentsOfURL:encoding:error: 即可下载该文件。根据您的要求,您可以使用 NSURLConnection 或 3rd 方库,如 ASIHttp(不推荐)、AFNetworking、MKNetworkKit 等。HTH。
  • 你好穆斯塔法,谢谢你的回复。实际上,服务器和数据库托管在机架空间上。那么,我认为我需要普通的旧网络服务来与服务器通信是正确的吗?或者使用托管在云上的服务器还有其他方法可以做到这一点?请原谅我的问题,因为我没有使用云服务器的经验。

标签: ios nsurlconnection asihttprequest rackspace-cloud rackspace


【解决方案1】:

所以,这就是我最终要做的,希望这足以(解决问题)。

这是我创建网络队列的方式:

- (ASINetworkQueue *)networkQueue {

    if (!_networkQueue) {
        _networkQueue = [[ASINetworkQueue alloc] init];
        [_networkQueue setShowAccurateProgress:YES];
        [_networkQueue setRequestDidFinishSelector:@selector(contentRequestDidSucceed:)];
        [_networkQueue setRequestDidFailSelector:@selector(contentRequestDidFail:)];
        [_networkQueue setShouldCancelAllRequestsOnFailure:NO];
        [_networkQueue setDelegate:self];
    }

    return _networkQueue;
}

这就是我的contentRequestDidSucceed: 方法的作用:

- (void)contentRequestDidSucceed:(ASIHTTPRequest *)request {
    // ASIHTTPRequest doesn't use HTTP status codes (except for redirection), 
    // so it's up to us to look out for problems (ex: 404) in the requestDidFinishSelector selector. 
    // requestDidFailSelector will be called only if there is the server can not be reached 
    // (time out, no connection, connection interrupted, ...)

    // In certain cases ASIHTTPRequest/ASINetworkQueue calls the delegate method requestDidFinishSelector,
    // instead it should call requestDidFailSelector. I've encountered this specific case with status code 206 (HTTP/1.1 206 Partial Content). In this case the file was not completely downloaded, so we'll have to re-process the request.
    if ([request responseStatusCode] != 200) {
        NSLog(@" ");
        NSLog(@"======= BEEP =======");
        NSLog(@" ");

        // We're double checking that the file was indeed not downloaded completely!
        // During internal testing, we encountered a case where download was successful
        // but we received 206 as the response code (maybe we received the cached value).
        unsigned long long progress = [request totalBytesRead] + [request partialDownloadSize];
        unsigned long long total = [request contentLength] + [request partialDownloadSize];

        if (progress != total) {
            NSString *downloadPath = [request downloadDestinationPath];
            NSString *temporaryDownloadPath = [self temporaryPathForFile:downloadPath];

            // Move the file at destination path to the temporary destination path (back again)    
            NSError *moveError = nil;
            [[[[NSFileManager alloc] init] autorelease] moveItemAtPath:downloadPath 
                                                                toPath:temporaryDownloadPath 
                                                                 error:&moveError];

            if (moveError) {
                NSLog(@"Failed to move file from '%@' to '%@'", downloadPath, temporaryDownloadPath);

                NSError *removeError = nil;
                [ASIHTTPRequest removeFileAtPath:downloadPath error:&removeError];

                if (removeError) {
                    NSLog(@"Failed to remove file from '%@'", downloadPath);
                }
            }

            // Call the requestDidFailSelector method
            [self contentRequestDidFail:request];

            // Don't continue
            return;   
        }        
    }

    // TODO: Process successful request!
    // . . .
}

如果有更好的处理方法,请告诉我。

【讨论】:

  • 做同样的事情,在部分下载时将文件从缓存移动到我自己的文件夹。相当骇人听闻的实现..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多