nginx如何处理web请求
首先要记住的是,Nginx的配置文件是逐层继承的,外层定义的配置项将会作为内层的默认配置,因此,最好将通用的配置项放在最顶层。当然,这种继承而来的默认配置可以在内层被重现。
常用的配置有三层,在配置文件中以块的形式呈现。HTTP块->server块->location块。
此外,有两种特殊的location块,事件(event)块和root块,HTTP块和事件块均在root块中。这两种块只包含了少量的配置信息,更多的则在其他的三种块中。
这些块各司其职。server块描述了一种在apache中称为虚拟服务器的结构,location块主要是针对URI。
一、基于域名的虚拟服务器
nginx首先确定使用哪一个server域来处理请求,下面的例子中有3个虚拟服务器监听*:80端口。
server {
listen 80;
server_name nginx.org www.nginx.org;
...
}
server {
listen 80;
server_name nginx.net www.nginx.net;
...
}
server {
listen 80;
server_name nginx.com www.nginx.com;
...
}
在上面的配置中,nignx根据HTTP请求“Host”的值,确定具体哪一个server接收web请求。如果“Host”不存在或者Host的值无法匹配任何sever中的$host_name,nginx就会把web请求送到默认的server中。如果没有定义default_server,默认将请求传递给第一个server。
请注意"default_server"是监听端口的属性,而不是主机名的属性。
参数“default_server” 是0.8.21后版本新增的内容. 此前的版本用“default”代替。
server { listen 80; server_name ""; return 444; }
在这里,我们设置主机名为空字符串以匹配未定义“Host”头的请求,而且返回了一个nginx特有的,非http标准的返回码444,它可以用来关闭连接。从0.8.48版本开始,这已成为主机名的默认设置,所以server_name ""可以省略。而之前的版本使用机器的hostname作为默认主机名。
二、处理基于IP和域名的虚拟主机
server {
listen 192.168.1.1:80;
server_name nginx.org www.nginx.org;
...
}
server {
listen 192.168.1.1:80;
server_name nginx.net www.nginx.net;
...
}
server {
listen 192.168.1.2:80;
server_name nginx.com www.nginx.com;
...
}
上面的配置中,nginx首先匹配IP地址和端口,然后在确定响应IP下的server_name,如果没有找到任何匹配的server_name,ngixn将请求传递给默认server。例如,当nginx收到来自 192.168.1.1:80 端口的请求www.nginx.com,
上例中没有定义默认server,那么这个请求将被传递到第一个server中。
nginx可以为不同的IP地址和端口定义多个默认server:
server {
listen 192.168.1.1:80;
server_name nginx.org www.nginx.org;
...
}
server {
listen 192.168.1.1:80 default_server;
server_name nginx.net www.nginx.net;
...
}
server {
listen 192.168.1.2:80 default_server;
server_name nginx.com www.nginx.com;
...
}
三、server_name的顺序问题
在一个Nginx虚拟主机中,可以绑定多个server_name,如:
server_name nginx.org www.nginx.org nginx.net www.nginx.net;
而server_name的先后顺序的不同,对PHP程序中使用$_SERVER["SERVER_NAME"]或getenv('SERVER_NAME')获取服务器域名是有影响的。
$_SERVER["SERVER_NAME"]或getenv('SERVER_NAME')获取的始终将是Nginx server_name配置中的第一个域名,这一点在程序开发中需要注意。这第一个域名就相当于Apache虚拟主机配置中的ServerName,后面的域名就相当于Apache的ServerAlias。
在某些情况下(具体可参考 wiki.nginx.org),Nginx 内部重定向规则会被启动,例如,当 URL 指向一个目录并且在最后没有包含“/”时,Nginx 内部会自动的做一个 301 重定向,这时会有两种情况:
1、server_name_in_redirect on(默认),URL 重定向为: server_name 中的第一个域名 + 目录名 + /;
2、server_name_in_redirect off,URL 重定向为: 原 URL 中的域名 + 目录名 + /。
当你有多个域名要指向同一个虚拟主机,并且你自己写 301 重定向规则把它们合并到某一个域名时,情况就更复杂了:
首先,nginx 检查 URL,如果符合条件,就用该规则(你写的)做第一遍重定向,接着,检查新生成的 URL,如果符合内部自动重定向之条件,就用前面提到的规则再做一次重定向。
至于 PHP 的 $_SERVER["SERVER_NAME"],在 nginx 中默认是由 nginx 的变量 $server_name 提供,这时它和重定向没有关系,始终是 server_name 设置中的第一个域名,但这是可以被改变的,在你的 nginx 配置中找到 fastcgi_param 部分,修改
fastcgi_param SERVER_NAME $server_name;
为
fastcgi_param SERVER_NAME $host;
但现在就要注意了,此时的 $_SERVER["SERVER_NAME"] 会受你写的和 nginx 自己的重定向规则所影响而变化。
四、如何确定web请求的location
server {
listen 80;
server_name nginx.org www.nginx.org;
root /data/www;
location / {
index index.html index.php;
}
location ~* \.(gif|jpg|png)$ {
expires 30d;
}
location ~ \.php$ {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
第一步,nginx使用字符串匹配找出最准确的location,这一步nginx会忽略location在配置文件出现的顺序。上面的配置中,只有唯一一个非正则匹配的location,也就是"/",它可以匹配任意的请求,一般作为最后一个选择。第二步,nginx会继续匹配正则表达式的location,匹配到第一个正则表达式后停止搜索。匹配到的location将被使用。正则表达式的匹配,按照配置中的顺序进行,出现在前的优先匹配。如果没有匹配到正则表达式,则使用第一步匹配的结果。
需要注意到的是,ngixn处理的URI中不包含查询字符串(query string)部分,因为这些查询字符串的不确定因素太多。
最后看一下上面的例子中,nignx是如何处理的:
1、“./logo.gif”的请求首先会匹配定位符”/”,其次是通用表达式”\.(gif|jpg|png)$”,因此它被第二个定位符所匹配.Nginx会使用指令”root /data/www”将请求映射到文件”/data/www/logo.gif”,之后文件被返回给客户端
2、“/index.php”的请求也一样,首先匹配定位符”/”,其次是通常表达式”\.(php)$”.因而它由后者处理,请求被传递给在localhost:9000监听的FastCGI服务.”fastcgi_param”指令将FastCGI的参数SCRIPT_FILENAME设置为”/data/www/index.php”,再由FastCGI服务器执行该文件.变量$document_root的值与”root”指令的值是相等的,变量$fastcgi_script_name的值等于所请求的url,如”/index.php”等等
3、带”/about.html”的请求只匹配定位符”/”,因此它将在这个定位符中得到处理,由”root /data/www”指令将请求映射到”/data/www/about.html”,最后文件才被返回给客户端.
4、处理”/”这样的请求就更复杂了,因为只匹配”/”定位符所以只能在其中处理.”index”指令会根据它的参数及”root /data/www”指令,测试该目录下是否有默认文件存在.例如,如果存在”/data/www/index.php”文件,请求会被内部重定向到”/index.php”,然后Nginx会据此再进行一次定位符搜索,看起来就像是新接收到一个请求命令.一般而言,被重定向的请求最后会由FastCGI服务处理.