使用BlobBaseClient.DownloadToAsync下载Blob仅返回206部分内容的解决方法
问题根因定位
你现在拿到空内容、看到206 Partial Content日志的问题,是三处代码逻辑错误叠加导致的,并非SDK本身的功能缺陷:
- 成功判断逻辑完全错位:
BlobBaseClient.DownloadToAsync本身内置了大文件分块并发下载能力,内部就是靠多次发送范围请求拉取不同分片、拼接成完整内容写入你传入的流对象。整个流程如果没有抛异常,就代表全量Blob已经完整写入,根本不需要靠返回的Response状态码判断是否成功。你硬卡Status == 200的判断,直接把本来成功的下载流程挡在了内容读取分支外面,全程没执行读流的代码,messageJson自然是空的。 - 流的位置没有重置:MemoryStream写完所有分片内容后,流指针是停在内容末尾位置的,就算进到读内容的分支,不把指针拨回开头,StreamReader从当前位置往后读,也只会读到空字符串。
- 取消令牌写法不规范:直接
new CancellationToken()的写法不符合SDK使用规范,这类写法生成的令牌没有关联任何取消源,虽然不会直接导致下载失败,但属于写法错误。 - 超大传输块配置冗余:
MaximumTransferSize = long.MaxValue的配置完全没必要,SDK本身对单次分片的大小有内部校验逻辑,设置过大的值反而可能触发传输校验异常。
你日志里看到的206状态,是SDK返回的Response对象承载的分片元数据状态,不是单次分片请求的响应,这个状态码本身不代表下载失败。
修正后的可直接运行代码
string messageJson = string.Empty; try { var blobBaseClient = new BlobBaseClient(_connectionString, _containerName, blobName); using var stream = new MemoryStream(); StorageTransferOptions storageTransferOptions = new StorageTransferOptions { InitialTransferSize = blobInitialChunkSize.Value * 1000000, MaximumConcurrency = blobChunkUploadMaxThreadCount.Value, // 替换掉原来的long.MaxValue,用合理的分片大小,比如100MB MaximumTransferSize = 100 * 1024 * 1024 }; BlobRequestConditions blobRequestConditions = new BlobRequestConditions(); // 只要方法没有抛出异常,就代表全量Blob已经完整写入传入的流 await blobBaseClient.DownloadToAsync( stream, blobRequestConditions, storageTransferOptions, CancellationToken.None); // 关键操作:把流指针从末尾重置到流开头,否则读取不到任何内容 stream.Position = 0; using StreamReader streamReader = new StreamReader(stream); messageJson = await streamReader.ReadToEndAsync(); } catch (Exception ex) { _logger.LogError(ex, "下载Blob失败,Blob名称:{BlobName}", blobName); throw; } return messageJson;
落地注意事项
- 不需要手动判断响应状态码:SDK内部已经做了全量校验,如果出现分片丢失、校验不通过、权限不足等问题,会直接抛出
RequestFailedException,不会返回带异常状态的Response对象。 - 206 Partial Content是正常的分片请求响应:SDK内部发的Range分片请求,本身就会拿到206的状态码,这是HTTP协议的标准行为,分块下载场景下SDK返回的Response状态为206完全正常,不代表下载不完整。
- 读取流内容前一定要确认流的Position:所有顺序写入的Stream,写入完成后指针都在末尾,不重置位置直接读是MemoryStream使用场景下的常见坑。
内容的提问来源于stack exchange,提问作者Pranav Singh
相关产品推荐
相关产品推荐

