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

如何实现服务器到Android应用的视频边看边加载及缓存?

解决Android视频边播边加载+缓存的服务器端配置问题

问题根源

你的控制器没处理范围请求(Range)——这是视频边播边加载的核心,Android播放器会分段请求视频内容,但你现在直接返回整个文件;同时Cache-Control: no-cache, no-store完全禁止了缓存,这两个问题导致播放器无法正常工作。

修正方案

1. 必须支持范围请求

播放器会发送Range: bytes=start-end请求头,服务器需要解析这个头,返回对应片段的视频流,同时返回206 Partial Content状态码,而不是固定的200 OK。

2. 调整HTTP头配置

  • 保留Accept-Ranges: bytes:告诉客户端服务器支持范围请求
  • 修改Cache-Control:设置为允许缓存的配置,比如public, max-age=86400(允许客户端缓存1天,可按需调整)
  • 移除无用头:Charset、Content-Transfer-Encoding对视频文件无效,无需设置
  • 必须设置Content-Length:完整请求返回文件总大小,部分请求返回片段大小
  • 部分请求需加Content-Range头:格式为bytes start-end/total,告知客户端当前返回的片段范围和总大小

3. 修正后的控制器代码

@GetMapping(value = "video/test/", produces = "video/mp4")
public ResponseEntity<InputStreamResource> getVideoByLink(HttpServletRequest request) throws IOException {
    File videoFile = new File("videoFile.mp4");
    long fileTotalLength = videoFile.length();
    HttpHeaders headers = new HttpHeaders();
    
    // 基础配置
    headers.setContentType(MediaType.valueOf("video/mp4"));
    headers.set("Accept-Ranges", "bytes");
    // 允许客户端缓存,max-age单位为秒
    headers.set("Cache-Control", "public, max-age=86400");

    // 处理范围请求
    String rangeHeader = request.getHeader("Range");
    if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
        // 解析Range参数,拆分起始和结束位置
        String[] rangeSegments = rangeHeader.substring(6).split("-");
        long start = Long.parseLong(rangeSegments[0]);
        // 如果没有指定结束位置,默认到文件末尾
        long end = rangeSegments.length > 1 ? Long.parseLong(rangeSegments[1]) : fileTotalLength - 1;
        end = Math.min(end, fileTotalLength - 1); // 防止超出文件大小
        long segmentLength = end - start + 1;

        // 读取指定范围的文件内容
        RandomAccessFile raf = new RandomAccessFile(videoFile, "r");
        raf.seek(start);
        byte[] segmentBytes = new byte[(int) segmentLength];
        raf.read(segmentBytes);
        raf.close();

        // 设置部分响应的头信息
        headers.setContentLength(segmentLength);
        headers.set("Content-Range", String.format("bytes %d-%d/%d", start, end, fileTotalLength));
        return new ResponseEntity<>(new InputStreamResource(new ByteArrayInputStream(segmentBytes)), headers, HttpStatus.PARTIAL_CONTENT);
    } else {
        // 处理完整文件请求
        headers.setContentLength(fileTotalLength);
        InputStream fullStream = new FileInputStream(videoFile);
        return new ResponseEntity<>(new InputStreamResource(fullStream), headers, HttpStatus.OK);
    }
}

4. 缓存实现说明

  • 服务器通过Cache-Control头告知Android播放器可以缓存视频内容,播放器会自动在本地存储已加载的片段,实现离线缓存播放
  • 如果需要服务器端层面的缓存(比如减少磁盘IO),可以结合Spring Cache或本地缓存库对视频片段做缓存,但普通场景下客户端缓存已足够满足需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:55:33