音频跨域加载失败的 CORS 问题
现象
控制台出现以下错误之一:
Access to fetch at '...mp3' from origin '...' has been blocked by CORS policy
No 'Access-Control-Allow-Origin' header is present on the requested resource
Media element error: The resource could not be loaded.
或者播放器就是一直转圈加载,不出声。
什么是 CORS
CORS(Cross-Origin Resource Sharing)是浏览器的安全机制。当你的网页(比如 https://example.com)尝试加载另一个域名的资源(比如 cdn-server.com/audio.mp3)时,浏览器会先发送一个预检请求,检查目标服务器是否明确允许跨域访问。
APlayer 会触发跨域的场景
| 场景 | 是否跨域 |
|---|---|
网页 https://a.com 加载 your-domain.com/a.mp3 | ❌ 同源,没问题 |
网页 https://a.com 加载 other-domain.com/a.mp3 | ✅ 跨域,需要 CORS |
网页 https://a.com 加载 jsDelivr CDN ... | ✅ 跨域(但 jsDelivr 支持 CORS) |
CDN 不同子域名 static-domain.com vs www-domain.com | ✅ 不同子域名也算跨域 |
解决方案一:让音频服务器支持 CORS(推荐)
在音频文件所在服务器的响应头里加上:
Access-Control-Allow-Origin: *
或者更严格地只允许你的域名:
Access-Control-Allow-Origin: your-site.com
具体怎么做取决于你的服务器:
Nginx
location ~* \.(mp3|wav|ogg|m3u8)$ {
add_header Access-Control-Allow-Origin *;
# 或者只允许你的域名
# add_header Access-Control-Allow-Origin your-site.com;
}
Apache (.htaccess)
<FilesMatch "\.(mp3|wav|ogg|m3u8)$">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
CDN(jsDelivr / Cloudflare 等)
大多数主流 CDN 已经默认开启了 CORS 支持。如果你用 jsDelivr、cdnjs、unpkg 来分发音频,通常不会遇到跨域问题。
对象存储(阿里云 OSS / 腾讯云 COS / Cloudflare R2)
在控制台里找到 CORS 设置,添加规则允许你的域名或 *。
解决方案二:音频代理到同源
如果音频服务器你控制不了(比如第三方服务、Meting API 返回的 URL),可以通过后端代理来转一下:
// 后端(Node.js Express 示例)
app.get('/audio-proxy', async (req, res) => {
const targetUrl = req.query.url;
const response = await fetch(targetUrl);
const buffer = await response.arrayBuffer();
res.setHeader('Content-Type', 'audio/mpeg');
res.send(Buffer.from(buffer));
});
// 前端 APlayer 使用代理 URL
const ap = new APlayer({
audio: [{
name: '歌曲名称',
url: '/audio-proxy?url=' + encodeURIComponent(actualUrl),
// ...
}]
});
这样对浏览器来说,请求的是你自己域名下的 /audio-proxy,不会触发跨域。
解决方案三:audio.crossOrigin 属性
APlayer 内部创建的 audio 元素有 crossOrigin 属性。某些场景下设置它能帮到:
// 这不是 APlayer 的参数,需要通过 audio 元素设置
ap.audio.crossOrigin = 'anonymous';
但这需要目标服务器已经正确配置了 CORS,否则还是会失败。
Meting API 场景
Meting API 返回的音频 URL 来自各音乐平台,可能会遇到跨域问题。这不是 APlayer 的问题,而是 Meting API 或目标服务器的限制。
如果用 MetingJS 时遇到跨域,可以:
- 尝试换一个音乐平台(网易云不行就换 QQ 音乐)
- 自己搭建一个 Meting API 实例并配置好 CORS
- 用上面的代理方案
排查步骤
遇到音频加载失败时,按以下顺序排查:
- 直接在浏览器地址栏打开音频 URL——能直接播放吗?404?跳转到别的域名?
- 打开 DevTools → Network——找到音频请求,查看 Response Headers 里有没有
Access-Control-Allow-Origin - 查看 Console——有没有明确的 CORS 错误提示
- 换一个域名测试——把音频放到你自己的服务器上试试能不能播放(如果能,确认是跨域问题)