Nginx 分片下载卡顿主因是缓存与 Range 请求语义不兼容:需配置 proxy_cache_key 含 $http_range、透传 Content-Range 等关键响应头、关闭 proxy_buffering 或调优缓冲参数,并启用 sendfile 优化传输。

大文件分片下载(如 MP4 的 byte-range 请求)卡顿,常被归因为 CDN 或前端问题,实际多是 Nginx 缓存与分片语义不兼容所致。核心矛盾在于:Nginx 默认缓存行为把每个 Range 请求当作独立响应缓存,而视频播放器连续发起多个小范围请求时,若缓存键(proxy_cache_key)未包含 Range 头、或缓存体被截断、或响应头缺失关键字段,就会导致部分分片命中失败、回源不稳定、首帧延迟高甚至播放中断。
确保 Range 请求统一缓存,避免碎片化
默认情况下,Nginx 不会将 Range 头纳入缓存键计算,导致同一 URL 的不同分片请求被存为多个缓存副本——不仅浪费空间,更易因缓存未命中引发回源抖动。必须显式声明缓存键包含 Range:
- 在对应 location 块中配置:
proxy_cache_key "$scheme$request_method$host$request_uri$http_range"; - 同步清理旧缓存:
proxy_cache_bypass $http_range;(仅对带 Range 的请求绕过缓存,用于调试) - 禁用无意义的 Vary 干扰:
proxy_ignore_headers Vary;(避免后端返回Vary: Range导致缓存分裂)
修复响应头缺失与截断,保障分片完整性
很多后端(尤其 Java/Node.js 服务)在处理 Range 请求时,会省略 Content-Range、Accept-Ranges 或返回不规范的 206 Partial Content,Nginx 缓存后可能丢弃这些头,或因缓冲区太小只缓存响应体前段,造成浏览器解析失败、seek 失效。
- 强制透传关键头:
proxy_pass_request_headers on;+ 显式添加:proxy_set_header Accept-Ranges "bytes"; - 增大响应头缓冲区:
proxy_buffer_size 128k;(防止大响应头被截断) - 验证缓存体是否完整:用
curl -H "Range: bytes=0-1023" -I http://your-domain/video.mp4检查返回的Content-Range和Content-Length是否匹配;再用curl -H "Range: bytes=0-1023" http://... | wc -c确认字节数一致
关闭代理缓冲或调优缓冲参数,适配流式分片
视频分片本质是短连接、高频、小响应体(通常几十 KB)、强时效性的请求。启用 proxy_buffering on 反而增加内存开销和首字节延迟,且易因 proxy_buffers 过小触发临时文件写入,拖慢 Range 响应。
- 推荐直接关闭缓冲:
proxy_buffering off;(适用于纯静态文件托管或后端已做 Range 处理) - 若必须开启(如需鉴权或日志注入),则调小缓冲粒度:
proxy_buffers 4 64k;+proxy_busy_buffers_size 64k;(避免大块缓冲浪费) - 禁用临时文件干扰:
proxy_max_temp_file_size 0;(设为 0 表示禁止落盘,强制内存或直传)
配合底层传输优化,提升分片响应效率
即使缓存逻辑正确,若内核传输层未优化,小分片仍可能因 TCP 小包、零拷贝未启用等问题产生延迟。
- 启用
sendfile on;+tcp_nopush on;(二者必须共存,让内核合并多个分片响应为单个 TCP 包) - 关闭
gzip和sub_filter(它们与 sendfile 冲突,会强制降级为 read/write 模式) - 对 MP4 文件路径单独配置:
location ~ \.mp4$ { add_header Accept-Ranges "bytes"; },确保浏览器明确支持分片


















