audio.src加载大音频会失败,因浏览器存在内存超限、网络无重试、ui卡顿三重限制;应改用mse或hls.js实现分片流式加载,并注意ios需用户手势触发play()。

直接用 <audio src="big.mp3"></audio> 加载几百MB的音频,99%会卡死、白屏或报 NETWORK_ERR。浏览器对单次 src 加载有内存和超时限制,尤其在移动端——这不是代码写得不对,是机制上就不支持。
为什么 audio.src 加大文件会失败
现代浏览器(包括 Chrome 128+、Safari 18、Firefox 120)对 <audio></audio> 的 src 加载做了三重约束:
- 内存:加载时需解码并缓存解码后帧,500MB MP3 可能瞬时占用 1.5GB 内存,触发 OOM 或强制 kill tab
- 网络:HTTP 请求无分片重试,一个 TCP 包丢包 → 整个请求失败,且无法断点续传
- UI 响应:
preload="auto"下,页面可能卡住数秒甚至十几秒,用户以为“打不开”就关掉了
用 MediaSource Extensions(MSE)手动喂流
这是唯一能真正控制大音频加载节奏的方式,适用于 >100MB 录音、会议回放、有声书等场景。关键不是“换标签”,而是接管数据流:
- 服务端必须提供可追加的格式:fMP4(推荐)、WebM 或带时间戳的 AAC 片段;裸 MP3/WAV 不行
- 前端创建
MediaSource,绑定到<audio></audio>的src,监听sourceopen后再调addSourceBuffer('audio/mp4; codecs="mp4a.40.2"') - 每次
fetch一个分片(建议 3–6 秒),拿到ArrayBuffer后先检查sourceBuffer.updating === false,再调appendBuffer() - 必须处理
updateend事件来链式加载下一段;忽略它会导致只播第一段就停住 - 时间戳(PTS)必须严格递增且连续,否则跳秒或卡死;可用
sourceBuffer.mode = 'sequence'简化,但需确保分片顺序正确
更稳的选择:用 hls.js 播 HLS 流
别从零手写 MSE 状态机。生产环境优先走标准化协议:
- 后端生成
.m3u8索引 +.aac或.ts分片(FFmpeg 一条命令就能切:ffmpeg -i in.mp3 -c:a aac -f hls -hls_time 4 -hls_list_size 0 out.m3u8) - 前端引入
hls.js,检测Hls.isSupported(),支持则用new Hls().loadSource('out.m3u8')绑定到<audio></audio> - Safari 原生支持 HLS,无需库;其他浏览器靠 hls.js 兜底,自动处理缓冲、重试、码率切换
- 注意 CORS:所有分片接口必须返回
Access-Control-Allow-Origin: *(若不带 credentials)或精确域名 -
preload="metadata"仍要设,否则控件不显示总时长;hls.js 会自己管理预加载逻辑
最容易被忽略的一点:iOS Safari 要求首次 play() 必须由用户手势触发(比如按钮点击),否则静音且不报错。哪怕你用 MSE 或 hls.js 接好了,没在 onclick 里调 audio.play(),音频照样不会响。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











