只写 src="xxx.mp3" 不保险,因firefox旧版默认禁用mp3解码器、ie9+对vbr编码报错、部分内网屏蔽audio/mpeg类型;浏览器按source顺序调用canplaytype(),遇"probably"即加载并停止遍历,故必须多格式+正确type+服务端mime匹配。

为什么只写 src="xxx.mp3" 一定不保险
MP3 在 Chrome、Safari、Edge 上基本能播,但 Firefox(尤其旧版)默认禁用 MP3 解码器;IE9+ 虽支持 MP3,却对某些 VBR 编码报错;更麻烦的是,部分企业内网或教育终端会主动屏蔽 MP3 MIME 类型(audio/mpeg),哪怕文件本身完好。只靠一个 src,等于把播放权交给浏览器的“运气”。
<source></source> 的顺序和 type 值必须严格匹配解码能力
浏览器不是“试播完一个不行再换下一个”,而是按 DOM 顺序调用 canPlayType(),只要返回 "probably" 就立刻加载、停止遍历。所以顺序错了,后面再好的格式也轮不到。
- 推荐 fallback 顺序:
<source src="a.opus" type="audio/ogg; codecs=opus"></source>→<source src="a.m4a" type="audio/mp4; codecs=aac"></source>→<source src="a.mp3" type="audio/mpeg"></source> -
type必须带codecs参数:写type="audio/ogg"不够,Safari 17.5 直接跳过;要写成type="audio/ogg; codecs=opus"才可能被识别 - 删掉没写
type的<source></source>:浏览器可能绕过 MIME 检查直接试播,失败后报MEDIA_ERR_DECODE却找不到源头
服务端配置比前端 HTML 更关键
前端写得再准,如果服务器返回的 Content-Type 错了、不支持 Range 请求、或跨域头缺失,音频照样静音或卡在 loading 状态。
- Nginx 必须显式声明 MIME:
add_type audio/ogg .opus;、add_type audio/mp4 .m4a;、add_type audio/mpeg .mp3; - 跨域音频(比如 CDN)必须返回
Access-Control-Allow-Origin: *,否则 Safari 连解码器都不初始化 - 所有音频文件需支持
Range请求(即 HTTP 206 Partial Content),否则拖动进度条、移动端 seek 都会失败
JS 播放时 play() 失败的常见真因
控制台报 NotAllowedError 很常见,但它只是表象;背后可能是格式、MIME、CORS 或 preload 设置共同导致的连锁反应。
- 确保
preload="metadata":它只拉取时长、采样率等元数据,避免首次play()因等待完整文件而超时 - 用户手势必须真实触发:不能在
setTimeout或load事件里调play(),iOS Safari 对此极其敏感 - 监听
error事件并检查audio.error?.code:值为4表示所有<source></source>都不可用,这时该回头查服务端响应头和网络请求状态
最常被忽略的点是:你改了 HTML 的 <source></source> 顺序,却没同步更新 Nginx 的 add_type 配置——结果浏览器拿到文件,但因为响应头是 application/octet-stream,直接判定“不支持”,连错误日志都不抛。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











