React+Video.js对接Java后端,MP4视频无法在Safari播放求助
问题:Safari无法通过接口加载MP4视频,其他环境正常
技术栈
- 前端:React + Video.js 7.20.1
- 后端:Java 8
前端代码
const playFunc = ()=> { if (!player.src.src) { player.src({ src: "http://192.168.0.86:8080/api/v1/" + "get-video/" + videoId, type: "video/mp4" }); } player.play(); };
后端代码
@GetMapping(value = "/get-video/{video-id}", produces = "video/mp4") public ResponseEntity<StreamingResponseBody> getVideo(@PathVariable("video-id") String videoId) throws IOException { String filePath = "HLC_Promo_-Small.mp4"; byte[] bytes = Files.readAllBytes(Paths.get(filePath)); return ResponseEntity .ok() .contentType(MediaType.valueOf("video/mp4")) .body(os -> os.write(bytes/*videoService.getVideo(videoId).getContent()*/)); }
测试情况
- Chrome、安卓Chrome:正常播放
- QuickTime:正常播放
- 直接拖拽到Safari:正常播放
- 通过接口加载到Safari:无法播放
问题原因及解决方法
1. 核心问题:缺少Range请求支持
Safari对视频流强制要求服务器支持Range分段请求(断点续传),当前后端一次性返回完整文件,未处理Range请求头,导致Safari无法正确解析视频流。
修改后端代码以支持Range请求:
@GetMapping(value = "/get-video/{video-id}", produces = "video/mp4") public ResponseEntity<?> getVideo(@PathVariable("video-id") String videoId, @RequestHeader(value = "Range", required = false) String range) throws IOException { Path filePath = Paths.get("HLC_Promo_-Small.mp4"); long fileSize = Files.size(filePath); // 处理无Range请求的情况 if (range == null) { byte[] bytes = Files.readAllBytes(filePath); return ResponseEntity.ok() .contentType(MediaType.valueOf("video/mp4")) .header("Accept-Ranges", "bytes") .contentLength(fileSize) .body(bytes); } // 处理Range分段请求 String[] rangeParts = range.replace("bytes=", "").split("-"); long start = Long.parseLong(rangeParts[0]); long end = rangeParts.length > 1 ? Long.parseLong(rangeParts[1]) : fileSize - 1; // 校验Range合法性 if (start > end || start >= fileSize) { return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE) .header("Content-Range", "bytes */" + fileSize) .build(); } long contentLength = end - start + 1; RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r"); raf.seek(start); byte[] bytes = new byte[(int) contentLength]; raf.read(bytes); raf.close(); return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT) .contentType(MediaType.valueOf("video/mp4")) .header("Content-Range", "bytes " + start + "-" + end + "/" + fileSize) .contentLength(contentLength) .body(bytes); }
2. 前端Video.js优化
避免直接调用play(),等待视频元数据加载完成后再播放,同时显式开启预加载:
const playFunc = ()=> { if (!player.src.src) { player.src({ src: "http://192.168.0.86:8080/api/v1/get-video/" + videoId, type: "video/mp4", preload: 'auto' }); } // 等待元数据加载完成后播放 player.one('loadedmetadata', () => { player.play(); }); };
3. 确认视频编码兼容性
确保视频采用Safari原生支持的H.264编码,可通过ffmpeg命令验证:
ffmpeg -i HLC_Promo_-Small.mp4
查看输出中Video:字段是否包含h264标识。
内容的提问来源于stack exchange,提问作者Сергей
相关产品推荐
相关产品推荐

