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

iOS Safari播放m3u8时如何检测video元素分片加载404错误

iOS Safari 原生video播放m3u8无法捕获分片404错误解决方案

iOS端Safari对原生HLS(m3u8)播放采用独立底层实现,分片加载失败(含分片404、中途断流、信号切断)的错误默认不会冒泡到<video>元素的标准error事件:播放器内部会默认发起数次重试,重试耗尽后直接卡停播放,不会对外抛出标准错误事件,这是Safari的已知实现差异,并非代码写法问题。

复现步骤

  • 正常加载并播放m3u8流地址
  • 播放过程中切断流传输信号,播放器停止播放,但error事件始终不触发,无法执行错误兜底逻辑

测试参考代码

<!DOCTYPE html>
<html>
<body>
<h1>The video autoplay attribute</h1>
<video id="VIDEO" width="320" height="240" controls autoplay playsinline></video>
<script>
    const linkPlay = "https://sgn-fpt-001-livecdn-vt.vieon.vn/7ed4de9c6e5740688d95878c8bd5a766/1654246367317/dvr_event/60b822a4-ef69-4886-b942-351ab352779a/playlist.m3u8"
    function init() {
        const video = document.getElementById("VIDEO")
        console.log(video)
        console.log(video.canPlayType('application/vnd.apple.mpegurl'))
        video.src = linkPlay
        video.load()
        video.addEventListener('error', (e)=> {
            console.log('error', e)
        })
    }
    init();
</script>
</body>
</html>

问题截图

可行解决方法

1. 无侵入兜底:等待状态超时检测(兼容性最好,支持所有iOS版本)

原生播放器在分片加载失败卡顿时,会触发waiting事件,且后续不会触发playing/canplay/timeupdate/progress这类播放/加载进度事件,可以基于这个逻辑做超时判断:

  • 监听waiting事件时启动计时器
  • 只要触发playing/canplay/timeupdate任意一个代表播放恢复的事件,就清空计时器
  • 如果计时器超过阈值(建议设置为1015秒,即23个分片的总时长,可根据自身业务的分片时长调整)仍未被清空,就判定为流加载失败,执行错误处理逻辑

示例代码:

const video = document.getElementById("VIDEO")
let errorTimer = null
const ERROR_TIMEOUT = 12000 // 12秒超时阈值

// 启动错误检测
function startErrorDetect() {
    clearErrorTimer()
    errorTimer = setTimeout(() => {
        // 超时判定为加载失败,执行对应错误逻辑
        console.log('流加载中断,触发错误处理')
        video.pause()
        // 可在此处添加错误提示、重试等业务逻辑
    }, ERROR_TIMEOUT)
}
// 清除错误检测
function clearErrorTimer() {
    if (errorTimer) {
        clearTimeout(errorTimer)
        errorTimer = null
    }
}
// 绑定检测事件
video.addEventListener('waiting', startErrorDetect)
video.addEventListener('stalled', startErrorDetect)
video.addEventListener('playing', clearErrorTimer)
video.addEventListener('canplay', clearErrorTimer)
video.addEventListener('timeupdate', clearErrorTimer)
// 保留原生error事件监听,捕获主列表加载失败等原生会抛出的错误
video.addEventListener('error', () => {
    clearErrorTimer()
    console.log('原生错误事件触发', video.error)
})

2. 精准捕获错误:使用hls.js接管HLS解析(适用于iOS 17.1+版本)

iOS 17.1之后的Safari开放了HLS的MSE播放权限,可以引入hls.js关闭原生HLS接管,由JS层实现m3u8解析和分片加载,此时所有分片请求错误(404、超时、断流)都可以通过hls.js的ERROR事件精准捕获,不会出现原生不抛错的问题。

注意:iOS 17.1以下版本不支持该方案,仍需要搭配上述超时兜底逻辑使用。

注意事项

  • 不要单独依赖原生error事件处理HLS播放错误,该事件在iOS Safari原生HLS场景下,仅会在主m3u8列表加载失败、视频格式完全不支持这类初始化阶段的致命错误时触发,播放过程中的分片错误、断流绝大多数场景都不会触发该事件。
  • 超时阈值不要设置过短(小于5秒),避免弱网下正常缓冲被误判为错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:27:35