📊 请求处理流程图
客户端请求
HTTP Request
HTTP Request
→
1. POST_READ
读取请求
读取请求
→
2. SERVER_REWRITE
Server 级重写
Server 级重写
→
3. FIND_CONFIG
查找 Location
查找 Location
→
4. REWRITE
Location 级重写
Location 级重写
→
5. POST_REWRITE
重写后检查
重写后检查
→
6. PREACCESS
访问前处理
访问前处理
→
7. ACCESS
访问控制
访问控制
→
8. POST_ACCESS
访问后处理
访问后处理
→
9. TRY_FILES
文件检查
文件检查
→
10. CONTENT
内容生成
内容生成
→
11. LOG
日志记录
日志记录
→
响应返回
HTTP Response
HTTP Response
💡 说明: 请求按照从上到下的顺序依次经过 11 个处理阶段,每个阶段可能有多个模块注册的处理函数。阶段之间可以跳转或终止。
🔄 请求处理序列图
┌────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌────────┐
│ Client │ │ Nginx │ │ Location │ │ Backend │ │ Log │
│ │ │ Core │ │ Matcher │ │ Server │ │ │
└───┬────┘ └────┬────┘ └────┬─────┘ └────┬────┘ └───┬────┘
│ │ │ │ │
│ HTTP Request │ │ │ │
│───────────────>│ │ │ │
│ │ │ │ │
│ │ POST_READ │ │ │
│ │ (realip 等) │ │ │
│ │ │ │ │
│ │ SERVER_REWRITE │ │ │
│ │ (server rewrite) │ │
│ │ │ │ │
│ │ FIND_CONFIG ──>│ │ │
│ │ (匹配 location) │ │ │
│ │<───────────────│ │ │
│ │ │ │ │
│ │ REWRITE │ │ │
│ │ (location rewrite) │ │
│ │ │ │ │
│ │ POST_REWRITE │ │ │
│ │ (重写检查) │ │ │
│ │ │ │ │
│ │ PREACCESS │ │ │
│ │ (limit_req 等) │ │ │
│ │ │ │ │
│ │ ACCESS ────────────────────────>│ │
│ │ (allow/deny) │ │ │
│ │ │ │ │
│ │ POST_ACCESS │ │ │
│ │ │ │ │
│ │ TRY_FILES │ │ │
│ │ (文件检查) │ │ │
│ │ │ │ │
│ │ CONTENT ──────────────────────>│ │
│ │ (proxy_pass/ │ │ │
│ │ fastcgi_pass) │ │ │
│ │ │ │ │
│ │<────────────────────────────────│ │
│ │ │ │ Response │
│ │ │ │ │
│ │ │ │ │
│ │ LOG ─────────────────────────────────────────>│
│ │ (access_log) │ │ │
│ │ │ │ │
│ HTTP Response │ │ │ │
│<───────────────│ │ │ │
│ │ │ │ │
📋 11 个处理阶段详解
1NGX_HTTP_POST_READ_PHASE - 读取请求后阶段
说明: 请求被完整读取后的第一个处理阶段,通常用于修改请求头或记录请求信息。
常用指令:
real_ip_header
set_real_ip_from
real_ip_recursive
mirror
典型应用:
- 获取客户端真实 IP(通过 X-Forwarded-For 等头)
- 请求镜像(流量复制)
- 请求头修改
# 获取真实 IP
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
2NGX_HTTP_SERVER_REWRITE_PHASE - Server 级重写阶段
说明: 在 server 块中执行的 URL 重写,此时尚未确定 location。
常用指令:
rewrite
return
set
if
典型应用:
- HTTP 强制跳转 HTTPS
- 域名重定向
- URL 规范化
- 旧 URL 重定向到新 URL
server {
listen 80;
server_name example.com;
# HTTP 强制跳转 HTTPS
return 301 https://$host$request_uri;
# 旧 URL 重定向
rewrite ^/old/(.*)$ /new/$1 permanent;
}
3NGX_HTTP_FIND_CONFIG_PHASE - 查找配置阶段
说明: 根据请求 URI 查找匹配的 location 配置。此阶段 Nginx 内部处理,无法直接干预。
匹配优先级:
= /path- 精确匹配(优先级最高)^~ /path- 前缀匹配,停止正则搜索~ pattern- 正则匹配(区分大小写)~* pattern- 正则匹配(不区分大小写)/path- 普通前缀匹配(优先级最低)
⚠️ 注意: 此阶段是 Nginx 内部处理,不执行任何模块 handler,仅确定使用哪个 location 配置。
4NGX_HTTP_REWRITE_PHASE - Location 级重写阶段
说明: 在 location 块中执行的 URL 重写。
常用指令:
rewrite
return
set
if
break
典型应用:
- URL 重写(伪静态)
- 条件重定向
- 变量设置
location /blog/ {
# 伪静态:将 /blog/123 重写为 /blog.php?id=123
rewrite ^/blog/([0-9]+)$ /blog.php?id=$1 last;
# 条件判断
if ($request_method = POST) {
return 403;
}
}
5NGX_HTTP_POST_REWRITE_PHASE - 重写后检查阶段
说明: 检查 rewrite 是否导致 URI 变化,如果变化则重新进入 FIND_CONFIG 阶段。
常用指令: 无(内部处理阶段)
⚠️ 注意: 如果 rewrite 使用了
last 或 redirect/permanent,会重新进入 location 匹配流程,可能导致循环。
6NGX_HTTP_PREACCESS_PHASE - 访问控制前阶段
说明: 在进行访问控制检查之前的预处理阶段。
常用指令:
limit_req_zone
limit_conn_zone
limit_req
limit_conn
add_header
典型应用:
- 请求速率限制
- 连接数限制
- 添加安全响应头
# 定义限流区域
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
# 应用限流
location /api/ {
limit_req zone=one burst=20 nodelay;
proxy_pass http://backend;
}
7NGX_HTTP_ACCESS_PHASE - 访问控制阶段
说明: 执行访问控制检查,决定请求是否被允许。
常用指令:
allow
deny
auth_basic
auth_basic_user_file
auth_request
典型应用:
- IP 黑白名单
- HTTP 基本认证
- 子请求认证
location /admin/ {
# IP 访问控制
allow 192.168.1.0/24;
deny all;
# 基本认证
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
8NGX_HTTP_POST_ACCESS_PHASE - 访问控制后阶段
说明: 访问控制检查后的处理阶段,用于满足 post_action 指令的需求。
常用指令:
post_action
典型应用:
- 请求后处理(如统计、通知)
⚠️ 注意: post_action 在主请求完成后执行,通常用于后台处理任务。
9NGX_HTTP_TRY_FILES_PHASE - 文件检查阶段
说明: 处理 try_files 指令,按顺序检查文件是否存在。
常用指令:
try_files
典型应用:
- SPA 应用路由支持
- 静态文件回退
- 自定义 404 处理
# SPA 应用配置
location / {
try_files $uri $uri/ /index.html;
}
# 静态文件服务
location /files/ {
try_files $uri $uri/ =404;
}
10NGX_HTTP_CONTENT_PHASE - 内容生成阶段
说明: 生成响应内容的核心阶段,多个模块可以注册 handler。
常用指令:
proxy_pass
fastcgi_pass
uwsgi_pass
scgi_pass
grpc_pass
return
root
alias
index
autoindex
stub_status
echo
典型应用:
- 反向代理
- FastCGI/PHP 处理
- 静态文件服务
- 目录列表
- 健康检查
# 反向代理
location /api/ {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态文件服务
location /static/ {
root /var/www;
expires 30d;
gzip on;
}
# PHP 处理
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
11NGX_HTTP_LOG_PHASE - 日志记录阶段
说明: 请求处理完成后的日志记录阶段。
常用指令:
access_log
log_format
open_log_file_cache
log_not_found
log_subrequest
典型应用:
- 访问日志记录
- 自定义日志格式
- 日志缓冲
# 自定义日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
# 应用日志格式
access_log /var/log/nginx/access.log main buffer=32k flush=1m;
📊 阶段与指令对应表
| 阶段 | 阶段名称 | 常用指令 | 是否可跳过 |
|---|---|---|---|
| 1 | POST_READ | real_ip_header, set_real_ip_from, mirror |
是 |
| 2 | SERVER_REWRITE | rewrite, return, set |
是 |
| 3 | FIND_CONFIG | (内部处理) | 否 |
| 4 | REWRITE | rewrite, return, set, if |
是 |
| 5 | POST_REWRITE | (内部处理) | 否 |
| 6 | PREACCESS | limit_req, limit_conn |
是 |
| 7 | ACCESS | allow, deny, auth_basic |
是 |
| 8 | POST_ACCESS | post_action |
是 |
| 9 | TRY_FILES | try_files |
是 |
| 10 | CONTENT | proxy_pass, fastcgi_pass, root, return |
否 |
| 11 | LOG | access_log, log_format |
是 |
💡 请求处理示例
示例场景: 用户请求
http://example.com/api/users,Nginx 如何处理?
http {
# ===== 阶段 1: POST_READ =====
# 获取真实 IP
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
# ===== 阶段 6: PREACCESS =====
# 定义限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
listen 80;
server_name example.com;
# ===== 阶段 2: SERVER_REWRITE =====
# 强制 HTTPS
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# ===== 阶段 7-10: 处理/api/请求 =====
location /api/ {
# ===== 阶段 4: REWRITE =====
# URL 重写(如有需要)
rewrite ^/api/v1/(.*)$ /api/$1 break;
# ===== 阶段 6: PREACCESS =====
# 应用限流
limit_req zone=api_limit burst=20 nodelay;
# ===== 阶段 7: ACCESS =====
# IP 限制
allow 192.168.0.0/16;
deny all;
# ===== 阶段 10: CONTENT =====
# 反向代理
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# ===== 阶段 10: CONTENT (静态文件) =====
location /static/ {
root /var/www;
expires 30d;
add_header Cache-Control "public, immutable";
}
# ===== 阶段 9: TRY_FILES (SPA 应用) =====
location /app/ {
try_files $uri $uri/ /app/index.html;
}
# ===== 阶段 11: LOG =====
access_log /var/log/nginx/access.log;
}
}
⚠️ 注意事项
rewrite 循环问题: 使用
last 标志时,会重新进入 location 匹配流程,可能导致无限循环。建议使用 break 或在重写后的 location 中避免再次匹配。
if 指令的局限性:
if 指令在 rewrite 阶段执行,行为可能不符合预期。避免在 if 中使用 set、rewrite 以外的指令。
阶段跳转: 某些指令会导致请求跳转到其他阶段,如
error_page 会创建内部重定向,try_files 可能直接返回 404。
性能提示:
- 将常用的访问控制放在靠前的阶段
- 避免过多的 rewrite 规则
- 使用
break代替last减少重新匹配 - 合理使用缓存和过期头减少后端压力