基于名字的虚拟主机
Nginx 首先会决定哪个服务器应该处理这次请求。我们先以一个简单的配置看起,这里三个虚拟主机都监听到端口 *:80:
server {
listen 80;
server_name example.org www.example.org;
...
}
server {
listen 80;
server_name example.net www.example.net;
...
}
server {
listen 80;
server_name example.com www.example.com;
...
}
在这一配置中,Nginx 仅仅根据请求头中的 "Host" 属性来决定将把当前请求路由到哪台服务器。如果该属性的值没有匹配到任意一台主机名,或者当前请求压根就没有包含这一属性,那么 Nginx 会将当前请求路由到这一端口的默认服务器。在上面的配置中,默认服务器是第一个 - 这是 Nginx 的标准默认行为。当然,也可以在 listen 指令中使用 default_server 参数来显式指定默认服务器:
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
default_server 参数自 0.8.21 版本起开始生效。在早期版本中应该使用 default 参数。
如何防止处理没有定义主机名的请求
如果不允许头中没有 "Host" 属性的请求,可以定义 server 以丢弃这些请求:
server {
listen 80;
server_name "";
return 444;
}
这里,server 名被设置为空串,这将匹配没有
“Host” 头的请求,之后一个特殊的非标准的 HTTP 码 444 会在关闭连接的同时返回。
自版本 0.8.48 起,这是 server 名的默认设置,因此可以忽略 server_name "" 的写法。在早期版本中,机器的主机名会被用作默认的 server 名。
基于名字和基于 IP 的混合的虚拟主机
我们继续看一下复杂一些的配置,这里虚拟主机监听不同地址:
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}
server {
listen 192.168.1.1:80;
server_name example.net www.example.net;
...
}
server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
...
}
在这一配置中,Nginx 会首先检测当前请求的 IP 地址和端口号是否匹配 server 块的 listen 指令。然后,Nginx 继续检测当前请求的 "Host" 属性是否匹配 server 块的 server_name 入口。如果服务器名没有找到,当前请求会被默认服务器处理。例如,一个端口 192.168.1.1:80 接收到的关于 www.example.com 的请求会被默认的 192.168.1.1:80 端口服务器处理,比如,第一台服务器,因为没有找到这一端口定义的 www.example.com。
上面说明过,默认服务器参数是监听端口的一个属性,可以针对不同端口定义不同的默认服务器:
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}
server {
listen 192.168.1.1:80 default_server;
server_name example.net www.example.net;
...
}
server {
listen 192.168.1.2:80 default_server;
server_name example.com www.example.com;
...
}
一个简单地 PHP 站点配置
我们看一下 Nginx 是如何为一个典型而又简单的 PHP 站点的请求选择定位的:
server {
listen 80;
server_name example.org www.example.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。如果没有任何正则表达式匹配这一请求,Nginx 会使用前面找到的最准确的前缀表达式 location。
注意所有 location 匹配测试只使用请求的 URI 部分,而不使用参数部分。这是因为请求串中的参数可以以多种方式给出,例如:
/index.php?user=john&page=1
/index.php?page=1&user=john
此外,一些人会使用以下请求串添加任何东西:
/index.php?page=1&something+else&user=john
现在我们看一下以上配置下的请求是如何被处理的:
- 一个 “/logo.gif” 的请求首先会被 “/” 匹配,然后被正则表达式 “\.(gif|jpg|png)$” 匹配,因此,它将被后一个 location 处理。使用指令 “root /data/www”,这一请求会被映射到文件 /data/www/logo.gif,然后文件被发送给客户端。
- 一个 “/index.php” 的请求也会先被 “/” 匹配,然后被正则表达式 “\.(php)$” 匹配。因此,它将被后一个 location 处理,这一请求会被传递给一个监听到 localhost:9000 的 FastCGI 服务器。fastcgi_param 指令设置 FastCGI 参数 SCRIPT_FILENAME 为 “/data/www/index.php”,FastCGI 将执行该文件。$document_root 变量等同于 root 指令的值,$fastcgi_script_name 变量等同于请求 URI,比如,“/index.php”。
- 一个 “/about.html” 的请求会仅仅被 location “/” 匹配,因此,它将被这一 location 处理。使用指令 “root /data/www”,这一请求会被映射到 /data/www/about.html 文件,这一文件会被发送给客户端。
- 处理一个 “/” 的请求有些复杂。它只会被前缀 location “/” 匹配,因此,它将由这一 location 处理。然后 index 指令会根据 “root /data/www” 指令检测 index 文件的存在。如果 /data/www/index.html 文件不存在,并且 /data/www/index.php 文件存在,然后这一指令会进行一个内部重定向到 “/index.php”,然后 Nginx 会再次寻找 location 对其进行匹配,就像这一请求时被一个客户端请求的一样。正如我们上面看到的,这一重定向请求将会最终被 FastCGI 服务器处理。
原文链接: http://nginx.org/en/docs/http/request_processing.html。