如何实现服务器到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
相关产品推荐
相关产品推荐

