7.1.6 请求处理流程与阶段(phases)

请求处理流程与阶段(phases)#

Nginx 的请求处理由阶段(phases)驱动,各阶段由不同类型模块挂载处理器,按固定顺序执行,实现从接收请求到响应输出的完整流水线。理解 phases 有助于定位请求被哪类模块接管、为何会被改写或终止。

原理草图(请求与阶段)

文章图片

主要阶段与典型模块
- post-read:请求读取完成后触发,少量模块使用。
- server-rewrite / rewrite:执行 rewriteif 等重写规则,可能触发内部重定向。
- find-config:location 匹配完成,确定最终配置上下文。
- preaccess / access:访问控制与认证,如 allow/denyauth_basiclimit_conn/limit_req
- try-files:根据文件存在性选择资源或内部跳转。
- content:内容生成阶段,反向代理、静态文件、FastCGI、uwsgi、gRPC 等在此提供响应。
- log:记录访问日志与统计。

安装与环境准备(示例)

# Debian/Ubuntu
sudo apt update
sudo apt install -y nginx

# RHEL/CentOS
sudo yum install -y nginx

# 启动与开机自启
sudo systemctl enable --now nginx

示例:用 rewrite + access + content 观察阶段行为
- 文件路径:/etc/nginx/conf.d/phases.conf

server {
    listen 8080;
    server_name localhost;

    access_log /var/log/nginx/phases.access.log main;
    error_log  /var/log/nginx/phases.error.log debug;

    # rewrite 阶段:将 /old -> /new
    location = /old {
        rewrite ^ /new last;
    }

    # access 阶段:只允许本机访问 /admin
    location /admin {
        allow 127.0.0.1;
        deny all;
        return 200 "admin ok\n";
    }

    # try_files + content 阶段:先找静态文件,否则走反向代理
    location / {
        root /var/www/html;
        try_files $uri @backend;
    }

    location @backend {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
    }

    # content 阶段:提供 /new 内容
    location = /new {
        return 200 "rewrite hit\n";
    }
}

启动测试后端与验证

# 启动一个简易后端(Python)
python3 -m http.server 9000

# 重新加载 Nginx
sudo nginx -t
sudo systemctl reload nginx

# 验证 rewrite 阶段
curl -i http://127.0.0.1:8080/old

# 验证 access 阶段(非本机将返回 403)
curl -i http://127.0.0.1:8080/admin

# 验证 try_files + 反向代理
curl -i http://127.0.0.1:8080/

命令与关键参数解释
- nginx -t:语法检查配置,避免 reload 后服务不可用。
- systemctl reload nginx:平滑重载,不中断已有连接。
- error_log ... debug:输出阶段执行细节,便于观察内部重定向与处理器链。
- try_files $uri @backend:先找静态文件,不存在则进入命名 location(content 阶段的代理模块)。

常见排错思路(带命令)
1. 重写异常或循环
bash # 观察 debug 日志中的 rewrite/internal redirect sudo tail -f /var/log/nginx/phases.error.log
关注是否多次出现 rewriteinternal redirect,必要时改用 break 或调整正则。

  1. 访问被拒绝
    bash curl -i http://127.0.0.1:8080/admin
    若返回 403/401,检查 access 阶段配置(allow/denyauth_basiclimit_req)。

  2. 代理不生效
    bash # 判断是否命中静态文件或被其他 location 截获 curl -i http://127.0.0.1:8080/ -H "Host: localhost"
    确认 try_files 路径与 root 是否正确,以及命名 location 是否被调用。

练习
1. 将 /oldrewrite 改为 rewrite ^ /new break;,比较 lastbreak 的差异。
2. 在 location / 中添加 limit_req,观察 access 阶段限流对响应码的影响。
3. 打开/关闭 error_log debug,对比日志中是否能看到阶段与内部重定向路径。