如何跟踪gzip编码的Web内容的下载进度?

时间:2022-03-17 15:24:29

I'm writting an iPhone client that downloads stuff from the net. Since the cellular network is not so fast, and files might be big, I wanted to improve upon the activity spinner with a progress bar.

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

So far so good, I'm using NSURLConnection and checking the Content-Length header to see how many bytes I will download. Then, in the -connection:didReceiveData: callback I append received data to my NSMutableData object and there I can track the size of the downloaded content so far vs expected bytes.

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

This all works until you have a server which supports gzip compression. A server using gzip compression will advertise x bytes as the size of the content. However, since NSURLConnection does the decompression behind the scenes, the data passed to the didReceiveData callback is already expanded. Therefore, the expected downloaded bytes are smaller than the actual received bytes, in the proportion of the compression ratio for the file.

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

This means that the progress bar overflows, since the expected bytes count is reached much earlier than expected. Something I could do when I control the server is send special headers for the gzip content to avoid the decompression made by NSURLConnection, but I can't control all the servers on the web.

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

Is there any hidden method for NSURLConnection to report the transferred bytes rather than expanded bytes? Do I have to code my own NSURLConnection to track transferred bytes and decompressed the gzip data myself for an accurate progress bar indicator? Maybe there is an alternative lower level Core Foundation API?

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

2 个解决方案

#1


1  

Use the ASIHTTPRequest library. That's my generic answer to pretty much all "how do I be a web client on the iPhone" questions, but it's particularly useful in this case.

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

Check this:

-(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 makes many powerful network operations very simple. I'm a big fan.

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

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

#2


5  

IIRC, you should be using the -expectedContentLength method of NSURLResponse, which, in my testing, returns NSURLResponseUnknownLength (-1) for gzipped content.

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

One workaround would be to disable sending of gzipped content by manually setting the Accept-Encoding header:

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

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

but of course, this defeats the point of gzipping content. :/

但是,当然,这会破坏内容压缩的重点。 :/

(If there's a better solution (that hopefully doesn't involve going lower-level than the NSURL* stuff) I'd love to know about it, too…)

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

#1


1  

Use the ASIHTTPRequest library. That's my generic answer to pretty much all "how do I be a web client on the iPhone" questions, but it's particularly useful in this case.

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

Check this:

-(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 makes many powerful network operations very simple. I'm a big fan.

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

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

#2


5  

IIRC, you should be using the -expectedContentLength method of NSURLResponse, which, in my testing, returns NSURLResponseUnknownLength (-1) for gzipped content.

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

One workaround would be to disable sending of gzipped content by manually setting the Accept-Encoding header:

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

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

but of course, this defeats the point of gzipping content. :/

但是,当然,这会破坏内容压缩的重点。 :/

(If there's a better solution (that hopefully doesn't involve going lower-level than the NSURL* stuff) I'd love to know about it, too…)

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