音视频跨域播放失败主因是Range请求触发CORS预检而Nginx未正确处理;需显式响应OPTIONS、允许Range请求头、暴露Content-Range和Accept-Ranges头、透传Range相关头且禁用缓存干扰。

音视频资源在跨域场景下常因 Range 请求触发 CORS 限制而播放失败,核心原因在于浏览器对带 Range 头的跨域请求会发起预检(OPTIONS),而 Nginx 默认未正确响应预检或未透传关键 CORS 头。解决的关键是:显式处理 OPTIONS 预检、允许 Range 相关请求头、并确保响应中携带正确的 Access-Control-Allow-Headers 和 Access-Control-Expose-Headers。
正确配置 CORS 响应头
Nginx 需明确允许音视频流所需的请求头与响应头,尤其涉及分片加载(如 Range、Accept-Ranges、Content-Range):
-
必须允许
Range请求头:在add_header Access-Control-Allow-Headers中加入Range -
必须暴露
Content-Range和Accept-Ranges:否则浏览器无法解析服务端返回的字节范围信息,导致MediaError或静音 -
建议开启
Vary: Origin,避免 CDN 或代理缓存错误的 CORS 响应
显式拦截并响应 OPTIONS 预检请求
带 Range 的跨域 GET 请求会触发预检,Nginx 必须直接返回 204(不返回实际内容),且响应头需完整:
- 使用
if ($request_method = 'OPTIONS') { ... }或更推荐的location = / { ... }+limit_except方式拦截 - 响应中必须包含
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Max-Age - 避免在 OPTIONS 响应中返回
Content-Length: 0或空 body,某些客户端(如 iOS Safari)对此敏感
透传 Range 请求与响应头,禁用缓存干扰
Nginx 作为反向代理时,需确保原始服务的 Range 行为不被覆盖或截断:
- 启用
proxy_set_header Range $http_range;和proxy_pass_request_headers on; - 关闭对 206 Partial Content 的缓存:
proxy_cache_bypass $http_range;+proxy_no_cache $http_range; - 确保后端服务返回
Accept-Ranges: bytes,Nginx 不应重写或删除该头
验证与调试要点
仅看响应头是否“存在”不够,需确认实际请求链路中的行为一致性:
- 用
curl -I -H "Origin: https://a.com" -H "Range: bytes=0-999" https://api.example.com/video.mp4检查是否返回 200/206 + 正确 CORS 头 - 检查预检请求(OPTIONS)是否返回 204,且所有
Access-Control-*头与主请求一致 - 在 Chrome DevTools 的 Network 面板中查看
Request Headers是否含Range,Response Headers是否含Content-Range和Access-Control-Expose-Headers - 若使用 CDN,确认其未剥离或覆盖自定义 CORS 响应头

















