Nginx处理请求的过程一共划分为11个阶段,按照执行顺序依次是 post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content 以及 log。
准备工作:host文件加入测试域名
sudo vi /etc/hosts
加入:
127.0.0.1 www.liudehua.com
目录
[阶段一 POST_READ](#阶段一 POST_READ)
[阶段二 SERVER_REWRITE](#阶段二 SERVER_REWRITE)
[阶段三 FIND_CONFIG](#阶段三 FIND_CONFIG)
[阶段四 REWRITE](#阶段四 REWRITE)
[阶段五 POST_REWRITE](#阶段五 POST_REWRITE)
[阶段六 PREACCESS](#阶段六 PREACCESS)
[阶段七 ACCESS](#阶段七 ACCESS)
[阶段八 POST_ACCESS](#阶段八 POST_ACCESS)
[阶段九 TRY_FILES](#阶段九 TRY_FILES)
[阶段十 CONTENT](#阶段十 CONTENT)
[阶段十一 LOG阶段](#阶段十一 LOG阶段)
阶段一 POST_READ
POST_READ阶段是nginx处理请求流程中第一个可以添加模块函数的阶段,任何需要在接收完请求头之后立刻处理的逻辑可以在该阶段注册处理函数。
nginx源码中只有realip模块在该阶段注册了函数,当nginx前端多了一个7层负载均衡层,并且客户端的真实ip被前端保存在请求头中时,该模块用来将客户端的ip替换为请求头中保存的值。
realip模块之所以在POST_READ阶段执行的原因是它需要在其他模块执行之前悄悄的将客户端ip替换为真实值,而且它需要的信息仅仅只是请求头。一般很少有模块需要注册在POST_READ阶段,realip模块默认没有编译进nginx。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
set_real_ip_from 127.0.0.1;
real_ip_header x-real-ip;
location / {
set $addr $remote_addr;
return 200 "real-ip: $addr";
}
}
错误:
nginx: [emerg] unknown directive "set_real_ip_from"
解决办法:加入realip模块重新编译
sudo ./configure --prefix=/home/tiger/nginx-1.22.1/nginx --with-stream --with-http_realip_module
sudo make & make install
测试请求:
curl -H "x-real-ip: 1.2.3.4" http://www.liudehua.com/
real-ip: 1.2.3.4
说明:
curl 工具的 -H 选项指定了额外的 HTTP 请求头
阶段二 SERVER_REWRITE
SERVER_REWRITE阶段是nginx中第一个必须经历的重要phase,请求进入此阶段时已经找到对应的虚拟主机(server)配置。在SERVER_REWRITE阶段中,请求还未被匹配到一个具体的location中。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
location /server_rewrite {
set b "a, hello world";
return 200 "args: $b";
}
set $a test_server_rewrite;
}
请求:
curl http://www.liudehua.com/server_rewrite
响应:
args: test_server_rewrite, hello world
阶段三 FIND_CONFIG
FIND_CONFIG阶段是寻找配置,是根据uri查找location配置。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
location / {
return 200 "test FIND_CONFIG";
}
}
test FIND_CONFIG
阶段四 REWRITE
REWRITE阶段为location级别的重写。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
location /rewrite {
root /home/tiger/nginx-1.22.1/nginx/html;
rewrite . /rewrite/index.txt break;
}
}
请求:
curl http://www.liudehua.com/rewrite
响应:
^^ ^^ ^_^ hello rewrite
阶段五 POST_REWRITE
该阶段不能注册handler,仅仅只是检查上一阶段是否做了uri重写,如果没有重写的话,直接进入下一阶段;如果有重写的话,则利用next跳转域往前跳转到FIND_CONFIG阶段重新执行。Nginx对uri重写次数做了限制,默认是10次
阶段六 PREACCESS
该阶段表明Nginx已经将请求确定到了某一个location(当该server没有任何location时,也可能是server),该阶段一般用来做资源控制,默认情况下,诸如ngx_http_limit_conn_module,ngx_http_limit_req_module等模块会在该阶段注册handler,
用于控制连接数,请求速率等。PREACCESS阶段使用的checker是默认的ngx_http_core_generic_phase函数。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
location /post_rewrite {
root /home/tiger/nginx-1.22.1/nginx/html;
limit_conn addr 1; #允许请求连接数
limit_rate 1k; #限定网络传输速率
}
}
错误:
nginx: [emerg] zero size shared memory zone "addr"
解决办法:加入zone模块重新编译
server标签同级别增加如下配置
limit_conn_zone $binary_remote_addr zone=addr:10m;
请求:
curl http://www.liudehua.com/post_rewrite
阶段七 ACCESS
该阶段的首要目的是做权限控制,默认情况下Nginx的ngx_http_access_module和ngx_http_auth_basic_module模块分别会在该阶段注册一个handler。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
auth_basic "User Authentication";
auth_basic_user_file /etc/nginx/.passwd-www;
location / {
root /home/tiger/nginx-1.22.1/nginx/html;
index index.html;
}
}
测试:安装工具htpasswd
sudo apt install apache2-utils
添加认证文件:
htpasswd -c /home/tiger/nginx-1.22.1/nginx/html/.passwd-www www
浏览器访问:
阶段八 POST_ACCESS
POST_ACCESS和POST_REWRITE阶段一样,只是处理一下上一阶段的结果,而不能挂载自己的handler,具体为如果ACCESS阶段返回了NGX_HTTP_FORBIDDEN或NGX_HTTP_UNAUTHORIZED(记录在r->access_code字段),该阶段会结束掉请求。
阶段九 TRY_FILES
TRY_FILES阶段仅当配置了try_files指令时生效,实际上该指令不常用,它的功能是指定一个或者多个文件或目录,最后一个参数可以指定为一个location或一个返回码,当设置了该指令时,TRY_FILES阶段调用checker函数ngx_http_core_try_files_phase来依此检查指定的文件或目录是否存在,如果本地文件系统存在某个文件或目录则退出该阶段继续执行下面的阶段,否则内部重定向到最后一个参数指定的location或返回指定的返回码。
该阶段也不能注册handler
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
location / {
root /home/tiger/nginx-1.22.1/nginx/html;
try_files $uri /test.html /index.htm /index.html;
}
}
以上配置会按顺序检查文件是否存在,顺序:$uri -> /test.html -> /index.htm -> /index.html
阶段十 CONTENT
CONTENT 阶段任务是生成响应内容并输出HTTP响应。
content阶段包含三个静态资源服务模块,ngx_index,ngx_autoindex,ngx_static用于当在location未使用任何content阶段的指令时处理URL请求。ngx_index和ngx_autoindex只作用于已/结尾的URI,其他由ngx_static执行。
ngx_index使用index指令用于查找首页文件,配合root指令实现,当找到文件后触发内部跳转而不是直接返回该文件,若都不存在则返回403。
nginx配置文件:
server {
listen 80;
server_name www.liudehua.com;
root /home/tiger/nginx-1.22.1/nginx/html;
location / {
index index.txt;
}
}
请求:
响应:
fdsssssssssssss
42333333
5433333333333
阶段十一 LOG阶段
LOG阶段主要的目的就是记录访问日志,进入该阶段表明该请求的响应已经发送到系统发送缓冲区。另外这个阶段的handler链实际上并不是在ngx_http_core_run_phases函数中执行,而是在释放请求资源的ngx_http_free_request函数中运行,这样做的原因实际是为了简化流程,因为ngx_http_core_run_phases可能会执行多次,而LOG阶段只需要再请求所有逻辑都结束时运行一次,所以在ngx_http_free_request函数中运行LOG阶段的handler链是非常好的选择。
备注:参考