Nginx的11个执行流程

1 Nginx简介

图片Web服务器市场份额

图片

Nginx [engine x] 最初由 Lgor Sysoev 编写。根据 Netcraft 的数据,到2020年9月,Nginx 服务或代理了25.76%站点,市场份额占到了约34.03%。

Nginx 被广泛用作:

· HTTP服务器

· 反向代理服务器

· 邮件代理服务器

· 通用的TCP/UDP代理

 

2 Nginx架构

图片

 

Nginx服务由一个Master进程和多个Worker进程构成。Master进程的主要职责是读取、解析配置文件,并维护工作进程。工作进程则负责实际的请求处理。

为了高效的在Worker之间分发请求,Nginx引入了依赖于操作系统的、高效的事件驱动模型。Worker进程的数量常常根据CPU核心数设置。这种模式的好处是每个worker进程都相互独立,无需添加锁,减少锁的开销。采用独立的进程并且不相互影响,一个进程进程退出并不影响其他的进程。一个worker进程的异常退出只会影响当前worker的上的请求,不影响其他worker的请求,降低了风险。

 

3 分Nginx处理http请求的11个阶段

Nginx 的11个执行阶段以及对应的http模块

图片

Nginx 的11个执行阶段的枚举类可以参考nginx源码中的ngx_http_core_module.h 中ngx_http_phases枚举

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,
    NGX_HTTP_SERVER_REWRITE_PHASE,
    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,
    NGX_HTTP_PREACCESS_PHASE,
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,
    NGX_HTTP_PRECONTENT_PHASE,
    NGX_HTTP_CONTENT_PHASE,
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

模块介绍可以参考Modules reference

11个执行阶段的各个模块的执行流程图:

图片

3.1 post_read 阶段介绍

Nginx的第一个阶段post_read 阶段是在正式处理请求之前工作的。在这个阶段刚刚获取了请求头的信息,还没有进行任何处理。我们可以拿到当前请求的原始数据,比如当前请求的真实IP。

在http协议中有两种方式获取用户IP:

· X-Forwardex-For 是用来传递 IP 的,这个头部会把经过的节点 IP 都记录下来。

· X-Real-IP:可以记录用户真实的 IP 地址,只能有一个。

3.1.1 ngx_http_realip_module 模块介绍

post_read涉及到的模块 ngx_http_realip_module 当前模块不会自动编译进Nginx中所以需要手动编译进入nginx源码文件夹中执行下列操作

./configure --with-http_realip_module

· 配置示例

set_real_ip_from 192.168.1.0/24;
set_real_ip_from 192.168.2.1;
set_real_ip_from 2001:0db8 :: / 32;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

· 内嵌变量

$realip_remote_addr #保留原始客户地址
$realip_remote_port #保留原始客户端端口

· 模块指令

当前模块有三个指令 set_real_ip_from、real_ip_header、real_ip_recursive

· set_real_ip_from

句法:	set_real_ip_from address | CIDR | unix:;
默认:	-
内容:	http,server,location

指定可信的地址,只有从该地址建立的连接,获取的 realip 才是可信的

· real_ip_header

句法:	real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;
默认:	real_ip_header X-Real-IP;
内容:	http,server,location

指定从哪个头部取真实的 IP 地址,默认从 X-Real-IP 中取,如果设置从 X-Forwarded-For 中取,会先从最后一个 IP 开始取

· real_ip_recursive

句法:	real_ip_recursive on | off;
默认:	real_ip_recursive off;
内容:	http,server,location

环回地址,默认关闭,打开的时候,如果 X-Forwarded-For 最后一个地址与客户端地址相同,会过滤掉该地址

· 实战 realIp 模块

修改nginx.conf 配置文件内容如下:

server {
        listen       80;
        server_name  abbila.com;
        set_real_ip_from 10.211.55.2;
        real_ip_recursive  off;
        #real_ip_recursive  on;
        real_ip_header  X-Forwarded-For;

        location / {
                return 200 "client real Ip is:$remote_addr  \n";
        }
」

上面的配置中设置了可信Ip为10.211.55.2,real_ip_recursive是关闭状态的,real_ip_header 从X-Forwarded-For获取。测试结果:

curl -H "X-Forwarded-For: 1.1.1.1,22.22.22.22,10.211.55.2" abbila.com
client real Ip is:10.211.55.2

然后把real_ip_recursive 打开 内容如下:

server {
        listen       80;
        server_name  abbila.com;
        set_real_ip_from 10.211.55.2;
        #real_ip_recursive  off;
        real_ip_recursive  on;
        real_ip_header  X-Forwarded-For;

        location / {
                return 200 "client real Ip is:$remote_addr  \n";
        }
」

测试结果

curl -H "X-Forwarded-For: 1.1.1.1,22.22.22.22,10.211.55.2" abbila.com
client real Ip is:22.22.22.22

通过上面两个实验可以看出来,如果real_ip_recursive关闭的话,获取的realIp为X-Forwarded-For的最后一个IP如果是打开状态的话那就把X-Forwarded-For中与可信IP重复的IP过滤掉然后取剩下的最后一个IP为realip。如果使用 X-Forwarded-For 获取 realip 的话,real_ip_recursive 需要打开。并且,realip 依赖于 set_real_ip_from 设置的可信地址。那么有人可能就会问了,那直接用 X-Real-IP 来选取真实的 IP 地址不就好了。这是可以的,但是 X-Real-IP 是 Nginx 独有的,如果客户端与服务器之间还有其他非 Nginx 软件实现的代理,就会造成取不到 X-Real-IP 头部,所以这个要根据实际情况来定。

3.2 rewrite 阶段

3.2.1 ngx_http_rewrite_model 模块介绍

rewrite 阶段设计到两个部分

· NGX_HTTP_REWRITE_PHASE

· NGX_HTTP_SERVER_REWRITE_PHASE

当前模块有 break、if、return、rewrite、rewrite_log、set、uninitialized_variable_warn 指令

· break 指令

句法:	break;
默认:	—
内容:	server,location,if

停止处理当前ngx_http_rewrite_module指令集 。

· if 指令

句法:	if (condition) { ... }
默认:	—
内容:	server, location

如果condition为true则执行{}中的内容。
condition可以为以下的一种或者几种:

· 变量名;如果变量的值为空字符串或“ 0”,则为false;否则为false。

· 使用“ =”和“ !=”运算符将变量与字符串进行比较。

· 使用“ ~”(区分大小写的匹配)和“ ~*”(区分大小写的匹配)运算符将变量与正则表达式进行匹配。正则表达式可以包含捕获。

这些捕获可用于以后在$1…$9变量中重用。负运算符“ !~”和“ !~*”也可用。如果正则表达式包含“ }”或“ ;”字符,则整个表达式应用单引号或双引号引起来。

· 使用“ -f”和“ !-f”运算符检查文件是否存在;

· 使用“ -d”和“ !-d”运算符检查目录是否存在;

· 使用“ -e”和“ !-e”运算符检查文件,目录或符号链接是否存在;

· 使用“ -x”和“ !-x”运算符检查可执行文件。

· return 指令

句法:	return code [text];
        return code URL;
        return URL;
默认:	—
内容:	server,location,if

状态码可以包含以下几种:

· Nginx 自定义

· 444:立刻关闭连接,用户收不到响应

· HTTP 1.0 标准:

· 301:永久重定向

· 302:临时重定向,禁止被缓存

· HTTP 1.1 标准:

· 303:临时重定向,允许改变方法,禁止被缓存

· 307:临时重定向,不允许改变方法,禁止被缓存

· 308:永久重定向,不允许改变方法

也可以

return 200 "the status code is 200";

可以返回对应的 error_page 可以参考:

http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page

· rewrite 指令

句法:	rewrite regex replacement [flag];
默认:	—
内容:	server,location,if

可选flag参数可以是以下之一:

· last
停止处理当前ngx_http_rewrite_module指令集, 并开始搜索与更改后的URI相匹配的新位置;

· break
ngx_http_rewrite_module与break指令一样, 停止处理当前的指令集 ;

· redirect
返回带有302代码的临时重定向;如果替换字符串不是以“ http://”,“ https://”或“ $scheme” 开头,则使用

· permanent
返回带有301代码的永久重定向。

· rewrite_log 指令

句法:	rewrite_log on | off;
默认:	rewrite_log off;
内容:	http,server,location,if

如果打开当前指令之后,会把 rewrite 的日志写入 logs/rewrite_error.log 日志文件中,

· set 指令

句法:	set $variable value;
默认:	—
内容:	server,location,if

可以为variable 设置对应的value值。该value可以包含文本,变量,他们的组合。

· uninitialized_variable_warn 指令

句法:	uninitialized_variable_warn on | off;
默认:	uninitialized_variable_warn on;
内容:	http,server,location,if

控制是否记录有关未初始化变量的警告。比如有些值没有找到等等。

· 实战一下rewrite模块:

nginx.conf 配置文件如下:

server {
        listen       80;
        server_name  abbila.com;
        location /break/ {
                rewrite ^/break/(.*) /test/$1 break;
        }

        location /last/ {
                rewrite_log on;
                rewrite ^/last/(.*) /test/$1 last;

        }

        location /test/ {
                return 200 "test page";
        }
}

测试下last:

curl abbila.com/last/ 
test page%

在测试下break:

curl abbila.com/break/  
    
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

通过测试可以看到break是跳过当前请求的rewrite阶段,并继续执行本请求的其他阶段,last与break最大的不同是,last会重新发起一个新请求,并重新匹配location,所以对于/last,重新匹配请求以后会匹配到/test/,所以最终对应的content阶段的输出是test page;然后看一下日志error.log

2020/10/16 15:51:25 [error] 29625#0: *26 "/usr/local/webserver/nginx/html/test/index.html" is not found (2: No such file or directory), client: 10.211.55.2, server: abbila.com, request: "GET /break/ HTTP/1.1", host: "abbila.com"
2020/10/16 15:51:36 [notice] 29625#0: *27 "^/last/(.*)" matches "/last/", client: 10.211.55.2, server: abbila.com, request: "GET /last/ HTTP/1.1", host: "abbila.com"
2020/10/16 15:51:36 [notice] 29625#0: *27 rewritten data: "/test/", args: "", client: 10.211.55.2, server: abbila.com, request: "GET /last/ HTTP/1.1", host: "abbila.com"

因为在break里面没有打开rewrite_log 在last中设置了rewrite_log 可以看到里面有rewrite日志信息,注意要把error.log的级别调成notice级别。

error_log  logs/error.log  notice;

3.3 preaccess 阶段

我们经常会遇到一个问题,就是如何限制每个客户端的并发连接数?如何限制访问频率?当前阶段设计到两个模块 ngx_http_limit_conn_module ngx_http_limit_req_module这两个模块都是默认编译到nginx中的可以使用–without-http_limit_req_module --without-http_limit_conn_module 移除。

3.3.1 http_limit_req_module 和 http_limit_conn_module 模块

req模块有四个指令 limit_req、limit_req_log_level、limit_req_status、limit_req_zone

与指对应的conn也存在四个指令limit_conn、limit_conn_log_level、limit_conn_status、limit_conn_zone

· limit_req 指令

句法:	limit_req zone=name [burst=number] [nodelay | delay=number];
默认:	—
内容:	http, server, location

定义共享内存(包括大小),以及 key 关键字和限制速率 rate 单位为 r/s 或者 r/m(每分钟或者每秒处理多少个请求)

· limit_req_log_level指令

句法:	limit_req_log_level info | notice | warn | error;
默认:	limit_req_log_level error;
内容:	http,server,location

如果超过了设置的阀值则把日记的记录级别修改为对应的级别。

· limit_req_status 指令

句法:	limit_req_status code;
默认:	limit_req_status 503;
内容:	http,server,location

为拒绝的服务请求设置对应点状态码。

· limit_req_zone 指令

句法:	limit_req_zone key zone=name:size rate=rate [sync];
默认:	—
内容:	http

设置共享内存区域的参数,该参数将保留各种键的状态。特别是,状态存储当前的过多请求数。该key可以包含文本,变量,他们的组合。具有空键值的请求不予考虑。

可以看到上面各个模块的执行顺序。当两个同事设置时,limit_req 在 limit_conn 处理之前,因此是 limit_req 会生效
如果不添加 nodelay,请求会等待,直到能够处理请求;添加 nodelay,在不超出 burst 的限制的情况下会立刻处理并返回,超出限制则会返回 limit_req_status状态。

· 实战:限流模块

nginx.conf 配置如下

limit_conn_zone $binary_remote_addr zone=addr:10m; #申请共享内存
server {
        listen       80;
        server_name  abbila.com;
        location / {
                limit_conn_status 500;
                limit_conn_log_level  warn;
                limit_rate 50;
                limit_conn addr 1;
                #limit_req zone=one burst=3 nodelay;
                #limit_req zone=one;    
        }
}

通过curl 访问

curl abbila.com/last/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

因为设置的limit_rate 是50个字节每秒,所以返回会特别慢,限制发生时设置的status是500所以同时发送两个请求会返回

curl abbila.com/last/
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

3.4. access 阶段

当前模块涉及到ngx_http_access_module模块、ngx_http_auth_basic_module 、ngx_http_auth_request_module

3.4.1 ngx_http_access_module 模块

当前模块默认编译到nginx中,可以使用–without-http_access_module

当前模块有两个指令allow、deny

· allow 指令

句法:	allow address | CIDR | unix: | all;
默认:	—
内容:	http,server,location,limit_except

允许访问指定的网络或地址。如果unix:指定了特殊值,则允许访问所有UNIX域套接字。

· deny 指令

句法:	deny address | CIDR | unix: | all;
默认:	—
内容:	http,server,location,limit_except

拒绝访问指定的网络或地址。如果unix:指定了特殊值,则允许访问所有UNIX域套接字。

3.4.2 ngx_http_auth_basic_module 模块

当前模块默认编译进nginx中,可使用 --without-http_auth_basic_module 指令移除
该模块允许通过使用“ HTTP基本身份验证”协议验证用户名和密码来限制对资源的访问。当开启这这个模块后,如果通过浏览器访问url时
会返回"401 Unauthorized" ,浏览器会返回一个用户名密码的对话框。
该模块有两个指令auth_basic、auth_basic_user_file

· auth_basic 指令

句法:	auth_basic string | off;
默认:	auth_basic off;
内容:	http,server,location,limit_except

· auth_basic_user_file

句法:	auth_basic_user_file file;
默认:	—
内容:	http,server,location,limit_except

这里面会用到 htpasswd(依赖httpd-tools安装包,如果自己试验可自行安装),这个工具可以用来生成密码文件,而 auth_basic_user_file 就依赖这个密码文件。
使用方法:

htpasswd -c file -b user password

· 实战:鉴权模块

nginx.conf 配置文件内容,通过上面命令生成 abbila.pass 文件。

server {
        listen       80;
        server_name  abbila.com;
        
        location / {
                auth_basic "close the web site";
                auth_basic_user_file abbila.pass;
        }
|

然后通过浏览器访问nginx 地址就可以看到:

图片

然后输入账号密码就可以正常访问页面了。

图片

3.4.3 ngx_http_auth_request_module 模块

当前模块没有编译到nginx中,可使用 --with-http_auth_basic_module 添加到nginx中。该模块可以将客户端输入的用户名、密码 username:password 通过 Base64 编码后写入 Request Headers 中。例如:abbila:abbila -> Authorization: Basic YWJiaWxhMTphYmJpbGE= 然后通过第三方程序解码后跟数据库中用户名、密码进行比较,Nginx 服务器通过 header 的返回状态判断是否认证通过。当前模块设计两个指令auth_request、auth_request_set

· auth_request 指令

句法:	auth_request uri | off;
默认:	auth_request off;
内容:	http,server,location

如果子请求返回2xx响应代码,则允许访问。如果返回401或403,则使用相应的错误代码拒绝访问。子请求返回的其他响应代码都被视为错误。

· auth_request_set 指令

句法:	auth_request_set $variable value;
默认:	—
内容:	http,server,location

授权成功后可以把赋值一些变量,可以包括鉴权请求的变量。

配置示例:

location /private/ {
    auth_request /auth;
    ...
}

location = /auth {
    proxy_pass https://auth.server.com/HttpBasicAuthenticate;#认证服务地址
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

根据认证服务地址返回的状态码来判断是否可以访问 /private/ 的请求。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Windows环境下,将Vue应用程序打包并部署到Nginx服务器上的流程如下: 1. 安装Node.js:在Windows上安装Node.js,官方网站提供了Windows安装包,您可以从 https://nodejs.org 下载并安装。 2. 创建Vue项目:打开命令提示符或PowerShell,并使用以下命令创建一个新的Vue项目: ``` vue create my-vue-app ``` 您可以根据需要选择使用默认配置或手动配置Vue项目。 3. 构建Vue项目:进入您的Vue项目目录,并执行以下命令来构建Vue项目: ``` cd my-vue-app npm run build ``` 这将在项目目录中创建一个名为`dist`的文件夹,并在其中生成用于部署的静态文件。 4. 安装和配置Nginx:下载适用于Windows的Nginx安装程序,您可以从 https://nginx.org/en/download.html 下载并安装最新版本。安装完成后,打开Nginx配置文件(通常位于`C:\nginx\conf\nginx.conf`),并进行以下配置更改: ``` http { ... server { listen 80; server_name localhost; root C:/path/to/my-vue-app/dist; index index.html; ... } ... } ``` 将`C:/path/to/my-vue-app/dist`替换为您Vue项目构建输出的实际路径。 5. 启动Nginx服务器:在命令提示符或PowerShell中,切换到Nginx安装目录(例如`C:\nginx`),然后执行以下命令启动Nginx服务器: ``` start nginx ``` 确保Nginx成功启动,并且没有报告任何错误。 6. 访问Vue应用程序:现在,您可以在浏览器中访问`http://localhost`来查看部署的Vue应用程序。 请注意,以上步骤仅为一般指导,实际操作可能会因个人配置和需求而有所不同。确保您正确配置了Nginx,并将路径和端口号等参数根据您的实际情况进行相应更改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凤舞飘伶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值