如何读取流的前几个字节后将其放回供其他消费者使用?
解决ASP.Net Core WebAPI中读取魔数后流式上传Blob的流缺失问题
核心问题是读取流的前几个字节后,流的位置指针会移动到已读取的位置,后续上传时会跳过这些字节。以下是两种可靠的解决方法:
方法一:启用请求流缓冲,支持位置重置
ASP.Net Core默认的请求流是不可回溯的,通过启用缓冲可以让流支持Seek操作,读取魔数后重置指针到开头即可。
[HttpPost("upload")] public async Task<IActionResult> Upload() { // 启用请求流缓冲,允许多次读取和位置重置 Request.EnableBuffering(); // 读取魔数字节(示例为PNG文件的4字节魔数) var magicByteLength = 4; var magicBytes = new byte[magicByteLength]; var readBytesCount = await Request.Body.ReadAsync(magicBytes, 0, magicByteLength); // 验证魔数(此处以PNG为例,可根据需要替换为目标文件的魔数) var validMagicBytes = new byte[] { 0x89, 0x50, 0x4E, 0x47 }; if (!magicBytes.Take(readBytesCount).SequenceEqual(validMagicBytes)) { return BadRequest("仅支持PNG格式文件"); } // 将流的位置重置到开头,确保上传时能读取完整文件内容 Request.Body.Position = 0; // 流式上传至Blob存储 await UploadFileToBlobStorage(Request.Body); return Ok("上传成功"); }
方法二:合并魔数字节与原流,构建完整流
如果场景中无法启用缓冲(比如处理超大文件,避免内存/磁盘缓冲压力),可以先读取魔数字节,再将这些字节与剩余流合并为一个完整的新流,再进行上传。
[HttpPost("upload")] public async Task<IActionResult> Upload() { var magicByteLength = 4; var magicBytes = new byte[magicByteLength]; var readBytesCount = await Request.Body.ReadAsync(magicBytes, 0, magicByteLength); // 验证魔数 var validMagicBytes = new byte[] { 0x89, 0x50, 0x4E, 0x47 }; if (!magicBytes.Take(readBytesCount).SequenceEqual(validMagicBytes)) { return BadRequest("仅支持PNG格式文件"); } // 构建包含魔数字节的完整流 using var combinedStream = new MemoryStream(); // 先写入已读取的魔数字节 await combinedStream.WriteAsync(magicBytes, 0, readBytesCount); // 再写入原流剩余内容 await Request.Body.CopyToAsync(combinedStream); // 重置流位置到开头 combinedStream.Position = 0; // 流式上传至Blob存储 await UploadFileToBlobStorage(combinedStream); return Ok("上传成功"); }
注意事项
- 方法一中,
EnableBuffering会将请求内容缓冲到内存或磁盘(超过内存阈值时自动写入临时文件),若处理大文件,建议配合配置RequestSizeLimit和MultipartBodyLengthLimit限制文件大小,避免资源耗尽。 - 方法二中,若处理超大文件,
MemoryStream可能占用过多内存,此时可改用临时FileStream替代,或使用管道流(PipeStream)来合并流,降低内存压力。
内容的提问来源于stack exchange,提问作者me.at.coding
相关产品推荐
相关产品推荐

