单个 <source> 容易失效是因为浏览器遇到首个网络或解码错误(如404/403/CORS)即停止尝试,不会自动切换后续 <source>;多个同格式URL需JS主动重试才能生效。

为什么单个 <source> 容易失效?
音频链接失效很常见:CDN 下线、权限变更、路径调整、跨域限制都可能导致 <audio> 加载失败并静音。浏览器遇到第一个 <source> 加载失败(HTTP 404/403,或 CORS 拒绝),**不会自动尝试下一个**——它只按顺序解析,一旦某个 <source> 返回网络错误或解码失败,就停在那里,后续 <source> 被忽略。
所以“多个 <source>”本身不是容错机制,而是靠浏览器对格式支持的 fallback(比如先试 ogg,不支持再试 mp3),但**对同一格式的多个 URL,浏览器并不做重试**。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
怎么让多个同格式音源真正生效?
必须借助 JavaScript 主动控制加载逻辑,绕过原生 <source> 的静态行为:
- 把所有备用 URL 放进一个数组,比如
['/audio/main.mp3', '/audio/backup.mp3', 'https://cdn.example.com/audio/fallback.mp3']
- 用
audio.src 逐个赋值,配合 audio.onerror 监听失败
- 每次赋值后调用
audio.load() 触发重新加载
- 设置最大重试次数(避免无限循环)和延迟(防止瞬间刷爆请求)
const audio = document.querySelector('audio');
const sources = [
'/audio/v1.mp3',
'/audio/v2.mp3',
'/audio/backup.mp3'
];
let attempt = 0;
function tryNextSource() {
if (attempt >= sources.length) return;
audio.src = sources[attempt];
audio.load();
attempt++;
}
audio.addEventListener('error', () => {
setTimeout(tryNextSource, 300);
});
要不要保留 HTML 里的 <source> 标签?
可以留,但别指望它做容错。它的作用仅限于:
- 提供初始加载源(第一个
<source> 会被优先使用)
- 声明不同格式(
type="audio/ogg" vs type="audio/mpeg"),供浏览器按支持度选择
- SEO 和可访问性(部分读屏工具会读取
<source> 的 media 或 type)
['/audio/main.mp3', '/audio/backup.mp3', 'https://cdn.example.com/audio/fallback.mp3']
audio.src 逐个赋值,配合 audio.onerror 监听失败audio.load() 触发重新加载<source> 标签?
可以留,但别指望它做容错。它的作用仅限于:
- 提供初始加载源(第一个
<source>会被优先使用) - 声明不同格式(
type="audio/ogg"vstype="audio/mpeg"),供浏览器按支持度选择 - SEO 和可访问性(部分读屏工具会读取
<source>的media或type)
如果你只用 MP3,写三个 <source src="a.mp3"></source><source src="b.mp3"></source> 是无效的——浏览器只认第一个。
容易被忽略的坑
-
audio.error 事件在某些情况下不触发(比如跨域资源返回 200 但内容为空,或服务器返回 HTML 页面而非音频流),建议加 audio.onstalled + timeout 双保险
- 移动端 Safari 对自动播放限制严格,即使加载成功,首次播放仍需用户手势触发
- 反复
load() 可能触发多次预加载,影响带宽和服务器压力,生产环境建议加缓存标识或服务端 302 跳转兜底
- 不要在
onerror 里直接 src = next 然后 play() —— 很可能因未就绪报 DOMException: The element has no supported sources
真要稳定,得把重试逻辑写实、测透,而不是靠 HTML 标签堆砌。
audio.error 事件在某些情况下不触发(比如跨域资源返回 200 但内容为空,或服务器返回 HTML 页面而非音频流),建议加 audio.onstalled + timeout 双保险load() 可能触发多次预加载,影响带宽和服务器压力,生产环境建议加缓存标识或服务端 302 跳转兜底onerror 里直接 src = next 然后 play() —— 很可能因未就绪报 DOMException: The element has no supported sources


















