Nginx 如何处理动态内容?有哪些配置方式?
Nginx 如何处理动态内容?有哪些配置方式?
Nginx 本身不执行动态脚本,它的角色是请求分发器——根据协议类型将动态请求转给后端应用服务器处理,自己只负责连接管理、缓冲、压缩和缓存等"外围工作"。常见的转发协议有四种:FastCGI、uWSGI、SCGI 和 HTTP 反向代理。
核心答案:四种协议的区别与选型
| 协议 | 典型后端 | 通信方式 | 适用场景 |
|---|---|---|---|
| FastCGI | PHP-FPM | Unix socket / TCP | PHP 项目,最常见 |
| uWSGI | Python (Django/Flask) | Unix socket / TCP | Python Web 应用 |
| SCGI | Ruby 等 | Unix socket / TCP | 较少使用 |
| HTTP Proxy | Node.js / Go / Java | HTTP/TCP | 通用,任何 HTTP 服务 |
选型原则:后端用什么语言/框架,就用对应协议。如果后端本身就是 HTTP 服务(如 Node.js),直接用 proxy_pass 做反向代理即可。
FastCGI 配置(PHP 项目最常用)
FastCGI 是 Nginx 处理 PHP 的标准方式。关键指令是 fastcgi_pass,它告诉 Nginx 把请求转发到哪里。
nginxlocation ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; # 这个参数必须设置,否则 PHP 找不到要执行的脚本 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; # 超时:后端响应慢时防止 Nginx 一直等 fastcgi_connect_timeout 60s; fastcgi_send_timeout 60s; fastcgi_read_timeout 60s; # 缓冲区:后端返回内容先缓冲再发给客户端 fastcgi_buffer_size 4k; fastcgi_buffers 8 4k; }
几个容易踩的坑:
SCRIPT_FILENAME必须拼成绝对路径,否则 PHP-FPM 报 404- Unix socket 比 TCP 快(省掉网络栈开销),但只能本机通信
try_files $uri =404防止 PHP 执行上传目录里的恶意脚本
uWSGI 配置(Python 项目)
Django、Flask 等 Python 框架常用 uWSGI 部署,Nginx 通过 uwsgi_pass 转发请求。
nginxupstream django_backend { server unix:/var/run/uwsgi/app.sock; server 127.0.0.1:8000; } server { listen 80; server_name example.com; location / { uwsgi_pass django_backend; include uwsgi_params; uwsgi_connect_timeout 60s; uwsgi_read_timeout 60s; } # 静态文件直接由 Nginx 处理,不走 uWSGI location /static/ { alias /var/www/html/static/; expires 1y; } }
核心区别:uWSGI 用自己的二进制协议,比 HTTP 更紧凑高效,但只有 Nginx 等 Web 服务器能直接对接。
HTTP 反向代理(Node.js / Go / Java)
如果后端本身就是一个 HTTP 服务,直接用 proxy_pass 转发,这也是微服务架构中最常见的方式。
nginxupstream nodejs_backend { server 127.0.0.1:3000; server 127.0.0.1:3001; } server { listen 80; server_name example.com; location / { proxy_pass http://nodejs_backend; # 透传客户端真实信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket 支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
为什么需要这些 header:后端拿到的 remote_addr 是 Nginx 的 IP 而非客户端 IP,必须通过 X-Real-IP 和 X-Forwarded-For 透传。WebSocket 升级也需要额外的 Upgrade 头。
FastCGI 缓存:让动态内容也变快
不是所有动态请求都要实时回源。比如文章详情页、列表页这类"准静态"内容,可以用 FastCGI 缓存大幅降低后端压力。
nginx# 在 http 块中定义缓存区 fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=fastcgi_cache:10m max_size=1g inactive=60m; server { location ~ \.php$ { fastcgi_cache fastcgi_cache; fastcgi_cache_valid 200 60m; # 200 响应缓存 60 分钟 fastcgi_cache_valid 404 1m; # 404 只缓存 1 分钟 fastcgi_cache_key "$scheme$request_method$host$request_uri"; # 登录用户等场景需要跳过缓存 set $skip_cache 0; if ($http_cookie ~* "comment_author|wordpress_logged_in") { set $skip_cache 1; } fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; add_header X-Cache-Status $upstream_cache_status; } }
缓存清理:inactive=60m 表示 60 分钟无访问自动清除。如果需要主动清除,可用 proxy_cache_purge 模块或直接删除缓存目录下的文件。
动态内容负载均衡
后端多实例部署时,Nginx 的 upstream 模块提供多种分发策略:
nginxupstream php_backend { least_conn; # 最少连接数优先 server 192.168.1.100:9000 weight=3; # 权重 3 server 192.168.1.101:9000 weight=2; # 权重 2 server 192.168.1.102:9000; # 默认权重 1 keepalive 32; # 保持长连接,减少握手开销 }
策略选择:
round-robin(默认):轮询,适合后端性能一致的场景least_conn:最少连接优先,适合请求处理时间差异大的场景ip_hash:同一 IP 固定到同一后端,适合需要会话保持的场景
Gzip 压缩:减少传输体积
动态内容通常是 JSON/HTML,压缩率很高,开启 Gzip 可以减少 60%-80% 的传输量。
nginxgzip on; gzip_vary on; gzip_min_length 1024; # 小于 1KB 不压缩,压缩反而更大 gzip_comp_level 6; # 6 是性能和压缩率的平衡点 gzip_types text/plain text/css application/json application/javascript application/xml;
安全配置要点
动态内容处理中,安全问题主要集中在两个方向:防止恶意脚本执行和限制请求大小。
nginx# 禁止访问敏感文件 location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|swp)$ { deny all; } # 防止上传目录中的 PHP 被执行 location ^~ /uploads/ { location ~ \.php$ { deny all; } } # 限制请求体大小 client_max_body_size 10m;
常见攻击面:上传一个 .php 文件到图片目录,然后直接访问执行。用 ^~ 前缀匹配 + 内部 deny 可以彻底堵住这个口。
追问:Nginx 处理动态内容的请求流程是什么?
客户端请求到达 Nginx 后,大致经历以下步骤:
- Nginx 接收请求,根据
location规则匹配到对应的转发配置 - 按协议(FastCGI/uWSGI/HTTP)将请求转发给后端应用服务器
- 后端处理完成,将响应返回给 Nginx
- Nginx 对响应做缓冲、压缩、缓存等处理
- 最终将响应返回给客户端
关键点:Nginx 在整个过程中只做"搬运工",不解析脚本内容。缓冲机制确保即使客户端读得慢,后端也能尽快释放连接;缓存机制则让重复请求直接从 Nginx 返回,后端完全不用参与。
追问:502 Bad Gateway 和 504 Gateway Timeout 有什么区别?
- 502:Nginx 成功连接到后端,但后端返回了无效响应(进程崩溃、端口未监听、协议不匹配等)
- 504:Nginx 等待后端响应超时(后端处理太慢,超过了
fastcgi_read_timeout或proxy_read_timeout)
排查思路:先看后端进程是否存活,再看 Nginx error log 中的具体错误信息,最后根据超时或连接失败调整对应参数。