如何分块生成字节数组并播放大视频?(ASP.NET Core场景)
大视频分块播放解决方案(ASP.NET Core)
问题根源
原方案将完整视频解密后转Base64存入ViewBag,本质是一次性把全量数据加载到内存,大视频会直接触发内存溢出;同时data URI本身存在大小限制,完全不适合大文件场景。正确思路是利用HTTP Range请求实现分段加载,让浏览器按需请求视频片段,后端对应分块解密并返回数据。
实现步骤
1. 后端Controller:支持Range请求的解密接口
不要将视频数据存入ViewBag,单独编写API接口处理视频请求。该接口解析Range请求头,读取对应分段的加密视频文件,分块解密后返回片段数据,并设置合规响应头,让浏览器识别分段加载能力。
示例代码:
[HttpGet("video/play/{fileName}")] public async Task<IActionResult> PlayEncryptedVideo(string fileName) { // 加密视频文件的物理存储路径 var encryptedFilePath = Path.Combine(_hostingEnvironment.WebRootPath, "encrypted-videos", fileName); if (!System.IO.File.Exists(encryptedFilePath)) return NotFound(); // AES解密参数(替换为你的实际密钥、IV) var key = Encoding.UTF8.GetBytes("YourAESKey12345678"); // 16/24/32位对应AES-128/192/256 var iv = Encoding.UTF8.GetBytes("YourAESIV12345678"); using var fileStream = new FileStream(encryptedFilePath, FileMode.Open, FileAccess.Read); var totalFileLength = fileStream.Length; // 处理Range请求头 var rangeHeader = Request.Headers.Range.ToString(); if (!string.IsNullOrEmpty(rangeHeader)) { // 解析Range格式,示例:"bytes=0-1023" var rangeParts = rangeHeader.Replace("bytes=", "").Split('-'); var startPos = long.Parse(rangeParts[0]); var endPos = rangeParts.Length > 1 && !string.IsNullOrEmpty(rangeParts[1]) ? long.Parse(rangeParts[1]) : totalFileLength - 1; var segmentLength = endPos - startPos + 1; // 定位到请求的文件起始位置 fileStream.Seek(startPos, SeekOrigin.Begin); // 初始化AES解密流 using var aes = Aes.Create(); aes.Key = key; aes.IV = iv; aes.Mode = CipherMode.CBC; // 与加密时的模式保持一致 aes.Padding = PaddingMode.PKCS7; // 与加密时的填充方式保持一致 using var decryptor = aes.CreateDecryptor(); using var cryptoStream = new CryptoStream(fileStream, decryptor, CryptoStreamMode.Read); // 读取对应分段的解密数据 var buffer = new byte[segmentLength]; await cryptoStream.ReadAsync(buffer, 0, (int)segmentLength); // 设置分段响应头 Response.Headers.AcceptRanges = "bytes"; Response.Headers.ContentRange = $"bytes {startPos}-{endPos}/{totalFileLength}"; Response.StatusCode = StatusCodes.Status206PartialContent; return File(buffer, "video/mp4"); // 根据视频格式替换正确的MIME类型 } else { // 无Range请求时返回完整视频(大视频不建议,可强制浏览器发起分段请求) using var aes = Aes.Create(); aes.Key = key; aes.IV = iv; using var decryptor = aes.CreateDecryptor(); using var cryptoStream = new CryptoStream(fileStream, decryptor, CryptoStreamMode.Read); Response.Headers.AcceptRanges = "bytes"; return File(cryptoStream, "video/mp4"); } }
2. 前端View:用HTML5 video标签加载
直接通过video标签的src指向上述API接口,浏览器会自动发送Range请求,按需分段加载视频,无需处理Base64或data URI。
示例代码:
<video controls width="800"> <source src="/video/play/your-encrypted-video.mp4" type="video/mp4"> 你的浏览器不支持HTML5视频播放 </video>
关键注意事项
- 加密参数一致性:解密时的AES模式、填充方式、密钥长度必须与加密环节完全匹配,否则解密数据会损坏。
- 内存优化:全程通过流处理数据,不要将完整解密视频存入内存,避免内存溢出。
- MIME类型匹配:根据视频格式设置正确的Content-Type(如video/webm、video/avi等),否则浏览器无法识别播放。
- 文件权限:确保后端进程拥有读取加密视频文件的权限,避免文件访问错误。
内容的提问来源于stack exchange,提问作者User
相关产品推荐
相关产品推荐

