NSURLErrorDomain:无法解码原始数据

时间:2012-07-12 18:19:12

标签: objective-c ios ios5 nsurlconnection ipod-touch

我正在使用自己的下载管理器下载一些文件。它工作了将近半年(甚至在将其发布到App Store后) 但昨天我有一些有趣的事情:

Error Domain=NSURLErrorDomain Code=-1015 "cannot decode raw data"
UserInfo=0x4c12e0
{
    NSErrorFailingURLStringKey=http://***/file.json.gz,
    NSErrorFailingURLKey=http://***/file.json.gz,
    NSLocalizedDescription=cannot decode raw data
    NSUnderlyingError=0x4dcec0 "cannot decode raw data"
}

一点背景:我有一个Web服务器,它给了我JSON和gzip压缩的JSON。

因此,当我尝试下载一个gzip压缩文件并且仅在iPod Touch 4G(5.1.1)上时,问题就出现了!

发生了什么事?我该怎么处理?这是一个Web服务器问题吗?

1 个答案:

答案 0 :(得分:2)

问题出在旁边 当iPhone收到gzip压缩数据时,它会自动解压缩。在这种情况下,Content-Length等于-1。因此,如果您想继续下载gzip压缩数据,那么制作Range标题并不是一个好主意:您不知道压缩数据的大小。
在我们的例子中,我们开始Range等于已经下载的数据,并且在某些情况下它超过了gzip压缩数据的大小(我甚至没有说它错了,文件已损坏!)。因此,Web服务器返回416 Requested Range not satisfiable,这就是调用NSURLConnection委托的didFailWithError方法时出现NSURLErrorCannotDecodeRawData错误的原因。

详细说明和我们的解决方案

在下载管理器中,我们有代码

NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setRange:NSMakeRange(progress, NSNotFound)];

其中progress是下载数据量。它存储在DB中以允许暂停并继续下载单个文件(例如,在应用程序重新启动之间的大文件)。当我们想要继续时,我们将Range标题设置为[进度; ∞)interval(从我们已经下载的偏移量接收数据)。

服务器(Apache,nginx等)在运行中将gzip编码应用于流。这对减少输出文件大小很有帮助,但结果你不知道整个gzip压缩文件的大小。所以它基本上意味着你不能暂停并继续下载gzip流。此外,下载的gzip压缩块在接收(NSURLConnection委托方法connection:didReceiveData:)时解压缩,因此您不会知道传递了多少gzip压缩数据。因此,您将不会创建正确的偏移量,服务器将从您不想要的偏移量返回数据,并且您最终的文件将被破坏,第二,一旦超过内容长度并接收{{1} }。

因此,没有任何一个浏览器或其他任何东西可以让您继续下载动态(根据请求生成)或gzipped内容。如果你想暂停并继续使用大型压缩文件(在我们的例子中为20 Mb JSON),要么将它们设置为静态并存档,要么继续gziping它们,只希望用户等到文件下载完毕。

所以我们选择了第二条路径,如果416未知(Content-Lenght),现在不设置范围。

-1