問題は次でした。
iPhoneはgzip圧縮されたデータを受信すると、自動的に解凍します。そしてContent-Lengthこの場合はに等しいです-1。したがって、gzipで圧縮されたデータのダウンロードを続行する場合は、Rangeヘッダーを作成することはお勧めできません。gzipで圧縮されたデータのサイズがわかりません。
私たちの場合、Rangeすでにダウンロードされたデータと同等のデータを開始し、場合によってはgzip圧縮されたデータのサイズを超えました(間違っているとは言えませんが、ファイルが破損しています!)。そのため、 Webサーバーが返さ416 Requested Range not satisfiableれ、NSURLConnectionデリゲートのdidFailWithErrorメソッドがNSURLErrorCannotDecodeRawDataエラーで呼び出されたのはそのためです。
詳細な説明とソリューション
ダウンロードマネージャーにはコードがありました
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setRange:NSMakeRange(progress, NSNotFound)];
progressダウンロードされたデータの量はどこにありますか。DBに保存され、単一のファイル(たとえば、アプリケーションの再起動の間に大きなファイル)のダウンロードを一時停止して続行できるようにします。続行する場合はRange、[progress; ∞)間隔(ダウンロード済みのオフセットからデータを受信するため)。
サーバー(Apache、nginxなど)は、オンザフライでストリームにgzipエンコーディングを適用します。これは出力ファイルのサイズを小さくするのに適していますが、結果としてgzip圧縮されたファイル全体のサイズがわかりません。つまり、基本的には、gzip圧縮されたストリームのダウンロードを一時停止して続行できないことを意味します。さらに、ダウンロードされたgzip圧縮されたチャンクは受信時に解凍されているため(NSURLConnectionデリゲートメソッドconnection:didReceiveData:)、どのくらいのgzip圧縮されたデータが渡されたかはわかりません。したがって、正しいオフセットを作成せず、サーバーは意図しないオフセットからデータを返し、結果のファイルは最初は破損し、次にコンテンツの長さを超えてを受信すると破損します416。
したがって、動的な(要求に応じて生成された)コンテンツまたはgzip圧縮されたコンテンツのダウンロードを続行できるブラウザなどはありません。大きな圧縮ファイル(この場合は20 Mb JSON)を一時停止して続行する場合は、静的にしてアーカイブするか、gzipを続行して、ファイルがダウンロードされるまでユーザーが待機することを期待します。
したがって、2番目のパスを選択し、不明な場合は範囲を設定しませんContent-Lenght(-1)。
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
if (urlResponse.expectedContentLength != NSURLResponseUnknownLength) {
[req setRange:NSMakeRange(progress, NSNotFound)];
}