版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原文出处,谢谢
原文出处: http://libiao.appspot.com/2010/01/nginx_processes_requests.html
Nginx是如何处理请求的?
1. 基于命名的虚拟服务器(Name-based virtual servers)
Nginx首先要确定由哪个服务器(server)来处理这个请求,如下面的简单的例子中,一共有3个虚拟主机,分别是:
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;
…
}
在上面的简单的配置中,nginx只需要简单的匹配下HTTP Request Header的Host字段就可以决定由那个虚拟服务器来处理该请求了。如果Host字段没有匹配上所有的虚拟服务器的名称,那么nginx就将其转到默认的服务器上进行处理。一般情况下,第一个虚拟服务器为默认的服务器。如上面配置中的为nginx.org为默认的虚拟服务器。如果你不想让第一个服务器作为默认的服务器,那么可以对上述的服务器配置上进行更改,如将nginx.net作为默认的服务器,则只需要在listen 80后加default_server即可。
server {
listen 80 default_server;
server_name nginx.net www.nginx.net;
…
}
注意,default_server是在版本0.8.21才引入的,如果之前的版本的话,请使用default,而不是default_server。
2. 怎么阻止一个没有定义服务器名称的请求
如在我的nginx里面没有定义这个虚拟服务器名称,但是有请求过来了,该怎么去阻止这个没有定义的服务器名称的请求呢?
只需要定义如下的server
server {
listen 80 default_server;
server_name _;
return 444;
}
选择一个不存在的域名_作为服务器名称,然后返回nginx特有的(非标准化的)的code 444来终止该连接。
3. 综合了基于命名的和基于IP的虚拟服务器
让我们来看看更加复杂一点的nginx的配置, 其监听了不同的地址
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地址和端口来检查listen项。然后根据HTTP请求中的HOST来检查server_name值,如果没有找到对应的server_name,那么将请求转向给默认的服务器。如在192.168.1.1:80上接收到一个www.nginx.com的请求,但是因为在192.168.1.1:80上没有定义nginx.com这个服务器名称,因此,有nginx.org来处理该请求。
同时上面也说了,默认的服务器是跟绑定的端口绑定在一起的,因此,如果不同的绑定端口下可以设置不同的默认服务器的,如下面的例子:
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;
…
}
即在192.168.1.1:80下设置默认的虚拟服务器为nginx.net,而在192.168.1.2:80下默认的为nginx.com。
4. 一个简单的PHP站点的配置
下面来看看如何给一个简单的PHP站点来设置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的,而是找最接近的location,如上面配置了3个location,但是只有万不得已的情况下,才会将请求转到第一个location,即/这个目录下。然后按照配置文件中定义的正则表达式来批判locations,如果找到对应的表达式,则停止搜索,使用搜索到的location。如果没有找到对应的正则表达式的搜索结果,则使用最接近的文本匹配的location。
需要注意的一点是,上面所有的location信息都是没有包含查询字符串(query string)的。因为查询字符串中包括了很多的显示方式,如:
/index.php?user=john&page=1
/index.php?page=1&user=john
同时也可能有其他的字符串在查询字符串中,如:
/index.php?page=1&something+else&user=john
下面我们来看看上面的配置如何来处理一个请求
l /logo.gif的请求。当用户请求/logo.gif过来的时候,首先被/这个location匹配上,然后由正则表达式\.(gif|png|jpg)$匹配上,因此使用后者。然后因为使用了root /data/www,那么/logo.gif请求就映射到文件/data/www/logo.gif上,并且将文件返回给用户。
l /index.php的请求。首先/index.php也是被/匹配上,然后被正则表达式\.php$匹配上。因此需要选择后者,将请求转发到location为\.php$上去。而在\.php$上其为一个fastcgi服务器,地址为localhost:9000。fastcgi_param设置FastCGI的参数SCRIPT_FILENAME为/data/www/index.php,然后FastCGI服务器执行该脚本。注意:$document_root等于上面root设定的值,即/data/www,而$fastcgi_script_name为请求的URI,即/index.php。
l /about.html的请求,因为该请求只是匹配上/这一项,因此,由location /来直接接受该请求,即将文件映射到/data/www/about.html,然后将结果返回给用户。
l /的请求。上述的三个location中,/的请求是最复杂的。如果一个请求只是匹配上/这一项,那么就由location /来处理该请求。Index指令就是告诉该location,如果在设定的root下(如上面为/data/www)下有index下的文件,即index.html或者index.php存在的话,则在内部需要做一次重定向。即如果在/data/www下有index.php,则重定向给/index.php,参考上面的/index.php的请求来处理。
备注: location的语法
location [=|~|~*|^~] /uri {}
其中~是区分大小写的正则表达式
~*为不区分大小写的正则表达式
= 为了提高效率,实行严格匹配,如果找到,停止搜索,执行该location的内容
^~ 是如果匹配上路径之后,不测试正则表达式了,停止搜索