Nginx 如何做动静分离?静态资源如何优化?
简化版
动静分离指把静态资源(HTML、CSS、JS、图片、字体等不变的文件)和动态请求(需要后端计算的接口)分开处理:静态资源由 Nginx 直接返回(Nginx 处理静态文件极快,还能零拷贝),动态请求由 Nginx 反向代理转发给后端应用。这样后端只处理业务逻辑、不用管静态文件,减轻负担、提升整体性能。静态资源优化则包括:开启 gzip 压缩、设置强缓存(Expires/Cache-Control)、sendfile 零拷贝、开启 HTTP/2、用 CDN 等。
详细版
动静分离配置:
server {
# 静态资源:Nginx 直接返回,设置长缓存
location ~* \.(html|css|js|jpg|jpeg|png|gif|ico|woff2)$ {
root /var/www/static;
expires 30d; # 强缓存 30 天
add_header Cache-Control "public";
access_log off; # 静态资源不记访问日志,省 I/O
}
# 动态请求:反向代理给后端应用
location /api/ {
proxy_pass http://backend;
}
}
# 静态资源优化
http {
sendfile on; # 零拷贝发送文件
tcp_nopush on; # 配合 sendfile,攒够一个包再发
gzip on; # 开启压缩
gzip_types text/css application/javascript application/json;
gzip_min_length 1k; # 小于 1k 不压缩
}
- 静态:Nginx 直接读文件返回 + 长缓存 + 压缩。
- 动态:proxy_pass 转发给后端。
- 优化点:gzip 压缩、强缓存、sendfile 零拷贝、tcp_nopush、HTTP/2、CDN。
完整版教学
一、为什么要动静分离
一个 Web 应用的请求分两类:
- 静态资源:HTML、CSS、JavaScript、图片、字体、视频等——内容固定、不需要后端计算,只要把文件原样返回即可。
- 动态请求:登录、下单、查询等接口——需要后端应用执行业务逻辑、查数据库才能生成响应。
如果让后端应用服务器(如 Tomcat)同时处理这两类,问题是:Tomcat 处理静态文件的效率远不如 Nginx,还白白占用了宝贵的应用线程去做「读文件返回」这种简单事,挤占了处理业务的资源。
动静分离就是各司其职:静态资源交给擅长的 Nginx 直接返回,动态请求才转发给后端应用。好处:
- 减轻后端负担:应用服务器只处理业务逻辑,不管静态文件。
- 提升静态响应速度:Nginx 处理静态文件极快(sendfile 零拷贝)。
- 便于独立优化和扩展:静态资源可以单独设缓存、上 CDN。
二、怎么配置动静分离
核心是用 location 按文件类型/路径区分,静态的 root 直接返回,动态的 proxy_pass 转发:
- 静态资源:用正则匹配文件扩展名(
~* \.(css|js|jpg|png...)$),配置root/alias指向静态文件目录,Nginx 直接读文件返回。 - 动态请求:匹配接口路径(如
/api/),用proxy_pass转发给后端应用服务器(或应用集群,配合负载均衡)。
更彻底的做法是静态资源单独部署(独立的静态资源服务器或对象存储 + CDN),Nginx 只做动态代理。
三、静态资源优化一:缓存(最重要)
静态资源内容基本不变,最有效的优化是让浏览器缓存它们,避免重复请求:
- 强缓存:通过
expires 30d或Cache-Control: max-age=2592000告诉浏览器「这个文件 30 天内直接用本地缓存,不用再来问我」。用户二次访问时,CSS/JS/图片直接从浏览器缓存读,根本不发请求,速度飞快、也省服务器带宽。 - 缓存与更新的矛盾:设了长缓存,文件更新了怎么办?用文件名哈希(指纹)——如
app.a1b2c3.js,文件内容变了文件名就变,浏览器当成新文件重新请求;没变则一直用缓存。这是前端工程化的标准做法。
四、静态资源优化二:压缩(gzip)
文本类静态资源(HTML、CSS、JS、JSON)压缩率很高(能压缩到原大小的 20~30%)。开启 gzip:
gzip on+gzip_types指定要压缩的类型(文本类)。- Nginx 在返回前把文件压缩,浏览器接收后解压。传输的数据量大幅减少,加载更快、省带宽。
- 注意:图片/视频等已经是压缩格式的不要再 gzip(压不动还浪费 CPU);
gzip_min_length设置太小的文件不压缩(压缩开销不划算)。 - 进阶用 Brotli 压缩(比 gzip 压缩率更高)。
五、静态资源优化三:sendfile 零拷贝与其他
- sendfile(零拷贝):
sendfile on。发送静态文件时,数据直接从磁盘(内核)送到网卡,不经过用户态拷贝,减少 CPU 和内存开销,大幅提升静态文件吞吐。 - tcp_nopush:配合 sendfile,让 Nginx 攒够一个完整的数据包再发送,减少小包数量,提高网络效率。
- HTTP/2:开启 HTTP/2,支持多路复用(一个连接并发传多个资源)、头部压缩,进一步加速。
- CDN:把静态资源分发到全国/全球的 CDN 边缘节点,用户就近获取,延迟最低——这是大流量站点静态资源优化的终极手段。
- access_log off:静态资源请求量大,可关闭它们的访问日志,减少磁盘 I/O。
六、常见误区与追问
| 考点 | 正确口径 |
|---|---|
| 静态资源 | 图片、CSS、JS 由 Nginx 直接返回或走 CDN |
| 动态请求 | 转发给应用服务处理 |
| 收益 | 减少应用压力,提升缓存命中和响应速度 |
location /static/ {
root /data/www;
expires 30d;
}
location /api/ {
proxy_pass http://app_backend;
}
动静分离的核心是让 Nginx/CDN 处理擅长的静态 IO,让应用专注业务计算。
- 误区:动静分离只是把文件放到不同目录。 关键是请求路径、缓存策略、CDN、压缩和应用转发边界。
- 误区:静态资源都不需要后端权限。 私有文件、付费资源仍要鉴权,可用签名 URL 或内部跳转。
- 误区:缓存时间越长越好。 长缓存要配合文件 hash,否则发布后用户可能一直拿旧资源。
- 追问:Nginx 返回静态文件为什么快? 事件驱动、sendfile、零拷贝和高效文件缓存减少应用层开销。
- 追问:静态资源如何优化? 开启 gzip/brotli、expires、etag、hash 文件名、CDN 和 HTTP/2。
- 追问:动态接口能缓存吗? 可缓存公共且可复用的动态结果,但要谨慎处理用户态和权限。
七、加强记忆
动静分离 = 静态资源(HTML/CSS/JS/图片)由 Nginx 直接返回,动态请求由 Nginx 反向代理转发给后端,让后端专注业务、Nginx 专注静态,各司其职提性能。配置用 location 按文件类型/路径区分(静态 root 返回、动态 proxy_pass 转发)。静态资源优化:① 缓存最关键(expires/Cache-Control 强缓存,配合文件名哈希解决更新);② gzip/Brotli 压缩文本类资源减小传输量(图片视频别压);③ sendfile 零拷贝 + tcp_nopush 提升发送效率;④ HTTP/2 多路复用、CDN 就近分发、关静态访问日志。口诀:静态归 Nginx、动态转后端;缓存 + 压缩 + 零拷贝 + CDN 一起上。