通过代码下载含文件夹的Azure API ZIP文件失败,浏览器下载正常
问题分析与修复方案
你的代码下载ZIP文件后损坏,主要有以下几个问题:
多余的Content-Type修改
手动设置response.Content.Headers.ContentType.MediaType = "application/zip";完全没必要,甚至可能干扰HttpClient对响应内容的正确解析。Azure API返回的响应头已包含正确的Content-Type,无需手动修改。流资源未正确管理
content和file流未使用using语句,导致流无法被正确关闭、刷新,部分数据可能留在缓冲区未写入磁盘,造成文件不完整。文件存在时未覆盖
File.OpenWrite会在目标文件已存在时追加内容,而非覆盖,新旧内容混合直接破坏ZIP文件结构。自动解压响应的潜在问题
默认情况下,HttpClient会自动处理带有Content-Encoding: gzip/deflate的响应。如果Azure API返回的ZIP文件本身被gzip压缩,HttpClient会自动解压,导致写入磁盘的是解压后的内容而非原始ZIP文件,最终损坏。
修复后的代码
public async Task GetArtifact(string url) { var client = CreateClient(); // 禁用自动解压,确保拿到原始ZIP字节流 client.DefaultRequestHeaders.AcceptEncoding.Clear(); var uri = new Uri(url); var percentage = 0.0; using HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); // 直接抛出非成功状态码异常,简化逻辑 var fileSize = response.Content.Headers.ContentLength; var fileName = response.Content.Headers.ContentDisposition.FileName; // 用File.Create覆盖现有文件,保证文件是全新的 using Stream fileStream = File.Create(fileName); using Stream contentStream = await response.Content.ReadAsStreamAsync(); var buffer = new byte[32768]; var readByte = 0L; int bytesRead; while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead); readByte += bytesRead; if (fileSize.HasValue) { percentage = Math.Round((double)readByte / fileSize.Value * 100, 2); Console.WriteLine($"{percentage}%"); } } }
关键修复点说明
- 禁用自动解压:通过
client.DefaultRequestHeaders.AcceptEncoding.Clear();避免HttpClient错误解压ZIP文件,确保获取原始字节流。 using语句管理资源:所有流和HttpResponseMessage都用using包裹,自动完成资源释放和流刷新,保证文件写入完整。File.Create替代File.OpenWrite:直接创建/覆盖文件,彻底避免旧内容干扰。- 简化状态码判断:用
response.EnsureSuccessStatusCode()替代手动判断,代码更简洁。
内容的提问来源于stack exchange,提问作者Damian Pietras
相关产品推荐
相关产品推荐

