You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何分块生成字节数组并播放大视频?(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 00:05:48