【问题标题】:How do I track the download progress of gzip encoded web content?如何跟踪 gzip 编码的 Web 内容的下载进度?
【发布时间】:2010-08-05 10:21:41
【问题描述】:

我正在编写一个从网上下载东西的 iPhone 客户端。由于蜂窝网络不是那么快,而且文件可能很大,所以我想改进带有进度条的活动微调器。

到目前为止一切顺利,我正在使用 NSURLConnection 并检查 Content-Length 标头以查看我将下载多少字节。然后,在-connection:didReceiveData: 回调中,我将接收到的数据附加到我的NSMutableData 对象中,在那里我可以跟踪到目前为止下载内容的大小与预期字节数。

在您拥有支持 gzip 压缩的服务器之前,这一切都有效。使用 gzip 压缩的服务器将宣传 x 字节作为内容的大小。但是,由于 NSURLConnection 在后台进行解压,所以传递给didReceiveData 回调的数据已经展开。因此,在文件压缩率的比例上,预期下载的字节数小于实际接收的字节数。

这意味着进度条溢出,因为预期的字节数比预期的要早得多。当我控制服务器时,我可以做的事情是发送 gzip 内容的特殊标头以避免 NSURLConnection 进行的解压缩,但我无法控制网络上的所有服务器。

NSURLConnection 是否有任何隐藏的方法来报告传输的字节而不是扩展的字节?我是否必须编写自己的 NSURLConnection 来跟踪传输的字节并自己解压缩 gzip 数据以获得准确的进度条指示器?也许有一个替代的较低级别的 Core Foundation API?

【问题讨论】:

    标签: iphone objective-c gzip nsurlconnection


    【解决方案1】:

    IIRC,您应该使用NSURLResponse-expectedContentLength 方法,在我的测试中,该方法为压缩内容返回NSURLResponseUnknownLength (-1)。

    一种解决方法是通过手动设置Accept-Encoding 标头来禁用压缩内容的发送:

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:yourURL];
    [request setValue:@"" forHTTPHeaderField:@"Accept-Encoding"];
    

    当然,这违背了压缩内容的意义。 :/

    (如果有更好的解决方案(希望不涉及比NSURL* 更低级别的东西)我也很想知道......)

    【讨论】:

    • 如果他在下载实际文件之前先在 HEAD 请求中请求大小,则不会。 HEAD 会有 Accept-Encoding @"",但实际请求不会。
    • 无论如何,使用另一个库(如 ASIHTTP)看起来是可行的方法(前提是它可以满足 OP 的要求)。
    • 我使用 HEAD 请求,将 Accept-Encoding 设置为 "" 来获取文件大小,然后使用 GET(此处不使用 Accept-Encoding)来获取文件内容,例如 @Kalle建议。在不影响任何第三方库的情况下,以正确的方式计算进度的魅力。
    【解决方案2】:

    使用 ASIHTTPRequest 库。这是我对几乎所有“我如何成为 iPhone 上的网络客户端”问题的通用答案,但在这种情况下它特别有用。

    检查一下:

    -(void)viewDidLoad {
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:myNSURLObject];
        request.delegate = self;
        request.downloadProgressDelegate = self.myUIProgressViewInstance; 
          //it'll update that progress bar with a percentage complete automatically!
          //or give it any custom class that responds to -progress!
        [request startAsynchronous];
    }
    
    - (void)requestFinished:(ASIHTTPRequest *)request
    {
        //do whatever to process the data you just got
    }
    

    ASIHTTP 使许多强大的网络操作变得非常简单。我是一个忠实的粉丝。

    http://allseeing-i.com/ASIHTTPRequest/

    【讨论】:

    • 我接受库作为无法在 NSURLConnection 级别完成的答案,您必须深入研究 CFNetwork API。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多