📊 请求处理流程图

客户端请求
HTTP Request
1. POST_READ
读取请求
2. SERVER_REWRITE
Server 级重写
3. FIND_CONFIG
查找 Location
4. REWRITE
Location 级重写
5. POST_REWRITE
重写后检查
6. PREACCESS
访问前处理
7. ACCESS
访问控制
8. POST_ACCESS
访问后处理
9. TRY_FILES
文件检查
10. CONTENT
内容生成
11. LOG
日志记录
响应返回
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 内部处理,无法直接干预。

匹配优先级:

  1. = /path - 精确匹配(优先级最高)
  2. ^~ /path - 前缀匹配,停止正则搜索
  3. ~ pattern - 正则匹配(区分大小写)
  4. ~* pattern - 正则匹配(不区分大小写)
  5. /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 使用了 lastredirect/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 中使用 setrewrite 以外的指令。
阶段跳转: 某些指令会导致请求跳转到其他阶段,如 error_page 会创建内部重定向,try_files 可能直接返回 404。
性能提示:
  • 将常用的访问控制放在靠前的阶段
  • 避免过多的 rewrite 规则
  • 使用 break 代替 last 减少重新匹配
  • 合理使用缓存和过期头减少后端压力