[译] nginx是如何处理Request的

670 查看

官文:How nginx processes a request

       Nginx首先判断哪一个Server应该被用来处理这个Request。举个简单的配置例子,三个虚拟Server都在80端口上listen。

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仅找到request的header的Host field,看一下request应该被rout到哪一个server。如果请求头的Host域找不到一个匹配的server的名称,或者request压根就不包含这个header的field,那么nginx将把request route到这个端口的默认server上。上面的配置中,默认的server就是第一个,nginx的标准默认行为就是认第一个。当然 ,也可以使用default_server参数在listen的指令中显示设置哪一个server应该是默认的。

server {
    listen      80 default_server;
    server_name example.net www.example.net;
    ...
}

       default_server参数从0.8.21版本开始有效。早期版本使用的是default参数。

       注意,默认服务器是listen端口的一个属性,其他的下面说。
如何阻止处理未定义server name的request。
       如果不带有Host header field的request要被禁止,丢弃request的server可以被这样定义。

server {
    listen      80;
    server_name "";
    return      444;
}

       这里,server name设置为空字符串,将匹配无Host header field的request,指定的nginx的非标准代码444被返回来关闭连接。
从0.8.48开始,这是server name的默认设定,所以server_name “” 可以被忽略。早期版本,机器的hostname被用作默认的server name。
混合基于name和基于IP的虚拟server
       看一下一些虚拟server监听在不同地址的更复杂的配置

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首先测对应server块的listen指令的request。然后测匹配Ip地址和端口的针对server块的server_name 实体 request Host header field。如果server name没有被发现,request将被default server处理。例如,www.example.com的request接受在192.168.1.1:80 端口将被 192.168.1.1:80 port的default server处理,例如被第一个,因为没有www.example.com被定义在这个端口。
       nginx如已述,default server是监听端口的属性,不同的default servers可以被不同的端口定义。

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如何选择位置来处理request,

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,通过字面的字符串而不管顺序。配置中仅有前缀location是/ 因为它匹配任何请求他将被用作保底。然后nginx检查被正则表达式给出的location按照配置文件中的顺序。第一个匹配的表达式终止搜索,nginx将使用这个location。如果没有正则表达式匹配,那么nginx使用最匹配前缀location。
       注意所有类型的location仅仅试探无参数的request行的URI部分。因为请求字符串中的参数可能会有多种方式。

/index.php?user=john&page=1
/index.php?page=1&user=john

       此外,任何人可能请求任何是在查询字符串

/index.php?page=1&something+else&user=john

       现在我们来看request将如何被处理。

/logo.gif
       这个request将被前缀位置 /首次匹配然后被正则表达式\.(gif|jpg|png)$匹配,因此,request被后location处理。使用指令root /data/www request被映射到文件/data/www/logo.gif,文件被送到客户端。

/index.php
       request也被/匹配然后被正则表达式\.(php)$匹配。所以请求被后面的location处理同时请求被传递到FastCGI server 监听在localhost:9000。fastcgi_param 指令设置FastCGI参数SCRIPT_FILENAME 为 /data/www/index.php,root + uri,FastCGI server执行这个文件。

/about.html
       被/匹配,被处理。使用指令root /data/www; request 被映射到root + uri /data/www/about.html。

/
       匹配的复杂。被前缀location / 匹配。因此被这个location处理。然后 index 指令填补参数和 root /data/www 指令一起,并测试文件是否存在。如果文件/data/www/index.html 不存在,/data/www/index.php 存在,那么指令要进行内部重定向(凡是请求中的没有uri指定文件的,使用index自动匹配上的,都会触发重定向),nginx重新匹配location,如果这个新生成的request是从客户端发来的一样,而不是直接返回相应资源。如我们所见,重定向请求最终被最后一个FastCGI server处理了。