5月28日 08:23

Nginx 如何处理动态内容?有哪些配置方式?

Nginx 如何处理动态内容?有哪些配置方式?

Nginx 本身不执行动态脚本,它的角色是请求分发器——根据协议类型将动态请求转给后端应用服务器处理,自己只负责连接管理、缓冲、压缩和缓存等"外围工作"。常见的转发协议有四种:FastCGI、uWSGI、SCGI 和 HTTP 反向代理。

核心答案:四种协议的区别与选型

协议典型后端通信方式适用场景
FastCGIPHP-FPMUnix socket / TCPPHP 项目,最常见
uWSGIPython (Django/Flask)Unix socket / TCPPython Web 应用
SCGIRuby 等Unix socket / TCP较少使用
HTTP ProxyNode.js / Go / JavaHTTP/TCP通用,任何 HTTP 服务

选型原则:后端用什么语言/框架,就用对应协议。如果后端本身就是 HTTP 服务(如 Node.js),直接用 proxy_pass 做反向代理即可。

FastCGI 配置(PHP 项目最常用)

FastCGI 是 Nginx 处理 PHP 的标准方式。关键指令是 fastcgi_pass,它告诉 Nginx 把请求转发到哪里。

nginx
location ~ \.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 转发请求。

nginx
upstream 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 转发,这也是微服务架构中最常见的方式。

nginx
upstream 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-IPX-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 模块提供多种分发策略:

nginx
upstream 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% 的传输量。

nginx
gzip 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 后,大致经历以下步骤:

  1. Nginx 接收请求,根据 location 规则匹配到对应的转发配置
  2. 按协议(FastCGI/uWSGI/HTTP)将请求转发给后端应用服务器
  3. 后端处理完成,将响应返回给 Nginx
  4. Nginx 对响应做缓冲、压缩、缓存等处理
  5. 最终将响应返回给客户端

关键点:Nginx 在整个过程中只做"搬运工",不解析脚本内容。缓冲机制确保即使客户端读得慢,后端也能尽快释放连接;缓存机制则让重复请求直接从 Nginx 返回,后端完全不用参与。

追问:502 Bad Gateway 和 504 Gateway Timeout 有什么区别?

  • 502:Nginx 成功连接到后端,但后端返回了无效响应(进程崩溃、端口未监听、协议不匹配等)
  • 504:Nginx 等待后端响应超时(后端处理太慢,超过了 fastcgi_read_timeoutproxy_read_timeout

排查思路:先看后端进程是否存活,再看 Nginx error log 中的具体错误信息,最后根据超时或连接失败调整对应参数。

标签:Nginx