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

Spring Boot+Angular应用MP4视频无法流式播放问题求助

问题分析及解决方案

核心问题:后端范围请求处理错误

你的后端代码在处理Range请求时,虽然计算了正确的起始/结束字节、设置了Content-Range响应头,但最终返回的还是完整的文件资源(FileSystemResource),并没有实际截取请求的字节片段。浏览器拿到完整文件,自然只能等下载完成后才会开始播放。

修复步骤

1. 修正后端范围请求的文件片段返回逻辑

替换返回完整FileSystemResource的代码,改为返回截取指定字节范围的InputStreamResource:

@GetMapping("/{id}")
public ResponseEntity<Resource> getVideo(@PathVariable("id") Long id, @RequestHeader HttpHeaders headers,
                                         Principal principal) throws IOException {
    Optional<Video> video = videoService.findOne(id, user);

    if (video.isEmpty()) {
        log.debug("Video not found");
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

    File videoFile = video.orElseThrow().getFileLocation();
    long fileLength = videoFile.length();
    List<HttpRange> httpRanges = headers.getRange();

    if (httpRanges.isEmpty()) {
        // 处理完整文件请求
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, "video/mp4")
                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength))
                .body(new FileSystemResource(videoFile));
    }

    // 处理范围请求
    HttpRange httpRange = httpRanges.get(0);
    long start = httpRange.getRangeStart(fileLength);
    long end = httpRange.getRangeEnd(fileLength);
    long contentLength = end - start + 1;

    // 创建截取指定范围的输入流
    InputStream inputStream = new FileInputStream(videoFile);
    inputStream.skip(start); // 跳过起始字节
    // 用BoundedInputStream限制读取长度,需引入Apache Commons IO,或自行实现类似逻辑
    InputStream rangeInputStream = new BoundedInputStream(inputStream, contentLength);

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set(HttpHeaders.ACCEPT_RANGES, "bytes");
    responseHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
    responseHeaders.set(HttpHeaders.CONTENT_RANGE, "bytes " + start + "-" + end + "/" + fileLength);
    responseHeaders.set(HttpHeaders.CONTENT_TYPE, "video/mp4");

    return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
            .headers(responseHeaders)
            .body(new InputStreamResource(rangeInputStream));
}

2. 确保视频文件本身支持流式播放

MP4文件的moov元数据原子如果存放在文件末尾,浏览器需要下载完整文件才能解析元数据,导致无法流式播放。可以用ffmpeg工具重新封装视频,把moov移到文件开头:

ffmpeg -i 原视频文件.mp4 -movflags faststart 处理后视频文件.mp4

3. 前端补充优化(可选)

  • 确认videoUrl()返回的是后端接口的正确地址,没有被拦截器或代理修改请求头
  • 保留preload="metadata"配置,让浏览器只预加载元数据,加快启动速度
  • 若需自动播放,添加autoplay muted属性(浏览器通常要求静音才能触发自动播放)

验证方式

修复后打开浏览器开发者工具的网络面板,查看视频请求:

  • 首次请求应返回206 Partial Content状态码,响应头包含Content-Range
  • 播放过程中会出现多个范围请求,说明流式播放已生效

内容的提问来源于stack exchange,提问作者Pampa Nello

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 02:55:04