M3U8 与 Nginx 部署指南:MIME、缓存、跨域一次配对
很多 M3U8 链接在本地能访问,放到线上却出现“能下载、不能播放”“清单正常、分片 404”或“浏览器直接报跨域”的问题,根源通常不是播放器,而是 Web 服务配置不完整。Nginx 部署 HLS 时,至少要把静态目录映射、MIME 类型、缓存策略和跨域响应头配齐,否则前端很难稳定播放。与普通静态文件相比,M3U8 的特点是清单和分片的访问行为不同,直播与点播的缓存策略也不同,因此配置不能一刀切。
1. 先确认目录结构与访问路径一致
部署前先把输出目录整理清楚,例如 /data/hls/live/stream/index.m3u8 旁边放同目录分片,或者主清单引用相对路径的多码率子清单。Nginx 中最容易出错的是 root 与 alias 的理解不清,结果 URL 与实际文件路径拼接错位。建议先用浏览器或 curl 验证 m3u8 和任意一个 ts 文件都能直接返回 200,再去调播放器,否则排障会被无效日志干扰。
2. MIME 类型一定要显式声明
部分环境没有默认识别 m3u8 与 ts,返回成通用二进制后,某些客户端仍能勉强播放,但浏览器兼容性会变差。常见做法是为清单返回 application/vnd.apple.mpegurl 或兼容的 HLS 类型,为分片返回 video/mp2t,如果是 CMAF/fMP4 片段,还要给出对应的 mp4 类型。MIME 类型不是“可有可无”的装饰,它会影响播放器、CDN 甚至调试工具对资源的识别方式。
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
3. CORS 要同时覆盖清单和分片
浏览器播放 HLS 时,请求的不只是入口 m3u8,还包括子清单、ts、key 文件,甚至预检请求。很多站点只给 m3u8 加了 Access-Control-Allow-Origin,结果首个清单能打开,后续分片被拦截,页面上只看到笼统的播放失败。稳妥做法是把整段 HLS 路径统一加跨域头,必要时放行 Range、Authorization 等请求头,并处理好 OPTIONS 预检。
4. 直播与点播缓存策略必须分开
点播清单通常固定不变,分片也稳定,可以让 CDN 和浏览器长期缓存;直播清单则会不断更新,如果缓存过长,播放器会一直拿到旧列表,表现为卡在某个时间点不再前进。实践里通常会把直播 m3u8 设置成极短缓存或直接不缓存,而分片保留适度缓存时间,以减轻源站压力。不要把“全部静态资源缓存一天”这样的通用策略直接套到直播路径,这会制造很隐蔽的线上问题。
5. 一份更接近实战的 location 规则
如果你的 HLS 文件统一放在一个目录下,可以按路径集中管理。核心思路是:目录映射正确、MIME 明确、清单和分片分别控制缓存,同时补齐跨域头。配置写完后,至少检查一次响应头,确保与设计一致。
location /hls/ {
alias /data/hls/;
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Headers "Range,Authorization,Content-Type" always;
}
location ~ \.m3u8$ {
expires -1;
add_header Cache-Control "no-cache" always;
}
location ~ \.ts$ {
expires 10m;
add_header Cache-Control "public, max-age=600" always;
}
6. 常见错误怎么快速判断
- 返回 403:通常是目录权限、鉴权规则或 CDN 回源权限有问题。
- 返回 404:多半是清单里的相对路径不对,或
alias映射错位。 - 浏览器报 CORS:说明请求已经发出,但响应头没有覆盖到实际访问的资源类型。
- 只有部分播放器能播:优先检查 MIME、编码格式和 key 文件是否可跨域访问。
7. 上线前的检查顺序
建议按“文件是否存在、URL 是否可达、响应头是否正确、播放器是否兼容”这个顺序排查。先用命令行确认资源本身没问题,再看浏览器 Network 面板是否有跨域、206、Range 或缓存命中异常。只要 Nginx 这一层配得稳定,后续播放器排障会简单很多。对于有直播业务的网站,最好把这套 Nginx 规则固化为模板,避免每次新加流路径时重复踩坑。