说明:“Nginx烂笔头”系列Blog是自己对Nginx官方文档的的翻译,用作阅读笔记便于日后查阅的成分居多,无关重要内容会删减,也可能会加入自己的理解。囿于个人水平,一些专业的名称翻译不会太准确,推荐查看Nginx官网原始文档。翻译内容如果有错误,欢迎指正。
本文翻译自Nginx官网How nginx processes a request网页文档。
摘要
本文主要描述了nginx是怎样处理不同配置下的请求。
基于名称的虚拟主机
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”字段来决定请求需要转发到哪里。如果Host的值没有匹配如何虚拟主机名或者是请求根本就没有包含Host这个字段,nginx会转发这个请求到这个端口默认的虚拟主机。在前述的配置,默认的虚拟主机是第一个,这个是nginx的默认行为。同样也可以在listen
指令中用default_server
参数明确的指出默认的虚拟主机。
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
default_server
参数在0.8.21版本后就可以使用了。在更早的版本,应该使用default
参数。
注意,默认虚拟主机是一个监听端口的属性而不是虚拟主机名称的。稍后会后更多的解释。
使用为定义的server name来阻止请求
如果想禁止没有Host字段的请求,可以用下面的配置来丢弃这个请求:
server {
listen 80;
server_name "";
return 444;
}
server名称设置成空字符串就可以匹配上这些不带Host请求头字段的请求,并且返回一个nginx特别的非标准的返回码来断开这个连接。
在0.8.48以后,这个设置在server上是默认的,所以,
server_name ""
这个配置key忽略。在之前的版本,服务器的hostname被用作为一个默认的server_name。
混合名称和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首先根据listen指令和server块指令来尝试匹配请求的ip和端口。然后根据匹配上的整个server块指令的server name来测试请求头的Host字段。如果没有找到匹配的server name,请求就会被默认的server处理。例如:192.168.1.1:80端口接收到一个www.example.com的请求会被转发到192.168.1.1:80的默认server处理,因为这个端口中没有www.example.com的server_name。
前面已经说过,default_server
是监听端口的属性,不同的监听端口可以配置不同的默认server。
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是怎样选择location来处理一个经典的简单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参数字符串。上面,仅有的location配置“/”会匹配上所有的请求,但是会被放到最后的优先级。然后,nginx会根据配置文件的顺序来查找匹配的正则表达式。如果没有正则表达式被匹配就会使用之前查找出的最长location配置。
注意,所有的location类型只会尝试匹配请求URI不包含参数的部分。因为参数的组合方式有很多种。
/index.php?user=john&page=1
/index.php?page=1&user=john
几个例子,说明nginx是如果处理请求的:
- 一个“/logo.gif”请求首先匹配了“/”前缀的location,然后匹配上了正则表达式".(gif|jpg|png)$",所以,它会被正在表达式所在的location块指令处理。因为这个locatin没有设置root指令,使用了server中的
root /data/www
,就是说,这个请求会被映射到/data/www/logo.gif
,然后返回这个文件给客户端。 - “/index.php”请求,先匹配上“/”,然后是正则表达式“.(php)$”。所以,它会被发送给监听着localhost:9000端口的FastCGI服务处理。(FastCGI方面java用的比较少,详情可以查看官方文档。)
- "/about.html"请求只会被“/”前缀匹配上,所以,它就使用这个location来处理了。
- 处理“/”请求比较复杂。当处理这个请求时,
index
指令会测试在参数配置的路径root /data/www
路径下是否有index文件。如果文件/data/www/index.html
不存在,但是/data/www/index.php
存在,nginx会做一个内部重定向到"/index.php",nginx会把它当成是从客户端发送过来的请求处理。在上面可以知道,这个请求会被FastCGI server处理。