nginx对静态文件不使用chunked编码,而是通过range请求支持、sendfile与read_ahead协同实现高效分块读取;默认发送content-length,提升缓存与cdn兼容性。

Nginx 本身不主动对静态文件做分块读取(Chunked Transfer Encoding)传输,这是它和动态服务的关键区别之一。它的默认行为是:只要知道文件大小,就直接发送完整响应并带上 Content-Length,从而跳过 Chunked 编码。真正实现“按需分片传输”的,是 Nginx 对 HTTP Range 请求 的原生支持,以及底层 sendfile + read_ahead 等机制协同完成的高效分段读取——不是协议层的 Chunked,而是系统级的、透明的、面向性能的分块处理。
静态资源的“分块读取”本质是 Range 支持与零拷贝协同
Nginx 对静态文件天然支持 Range 请求(如视频拖拽、大文件断点续传),客户端发来 Range: bytes=0-1023,Nginx 不会把整个文件读进内存再切片,而是:
- 直接调用
sendfile()或pread()定位到指定偏移量 - 只读取请求范围内的数据块(例如 64KB 或 1MB 片段)
- 将该片段通过 socket 零拷贝发出,并返回
206 Partial Content和精确的Content-Range
这个过程对用户透明,无需额外配置,只要:
- 文件放在本地磁盘(
root或alias指向真实路径) -
sendfile on;已启用(推荐) -
tcp_nopush on;配合使用,提升大块数据包效率
如何让大文件读取更高效(非 Chunked,但效果类似)
Nginx 提供了几个关键指令,让“分块式读取”更智能、更少 I/O 开销:
read_ahead 1m;
在读取当前块时,提前预加载后续最多 1MB 数据到 page cache,减少磁盘寻道,特别适合连续读取(如视频、PDF)directio 4m;(配合sendfile off使用)
对 ≥4MB 的文件启用直接 I/O(绕过内核 page cache),避免大文件缓存挤占内存;此时 Nginx 会以 4MB 为单位分块读取并传输open_file_cache max=1000 inactive=30s;
缓存文件句柄、inode、mtime 等元信息,避免每次Range请求都open()/stat(),大幅降低小范围请求的系统调用开销
为什么不该依赖 Chunked 来传输静态资源?
- Chunked 是传输编码(Transfer-Encoding),不是内容分片逻辑
- Nginx 的
proxy_cache和fastcgi_cache默认不缓存 Chunked 响应,因为无法可靠计算长度、补Content-Length - 若后端(如 Spring Boot)误返回 Chunked 给静态路径,会导致缓存失效、
X-Cache-Status: MISS、首字节延迟上升 - 静态文件走
root/alias时,Nginx 总能获取真实文件大小 → 自动设Content-Length→ 协议禁止 Chunked → 更稳定、更易缓存、CDN 兼容性更好
实际配置建议(针对大静态文件)
location ~* \.(mp4|avi|pdf|zip)$ {
root /data/files;
sendfile on;
tcp_nopush on;
read_ahead 2m;
open_file_cache max=500 inactive=60s;
open_file_cache_valid 2m;
expires 7d;
add_header Accept-Ranges bytes; # 显式声明支持 Range(虽默认已有)
}
不复杂但容易忽略











