一、基于名字的虚拟主机
Nginx首先选定由哪一个虚拟主机来处理请求。让我们从一个简单的配置(其中全部3个虚拟主机都在端口*: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的默认虚拟主机——这是nginx的默认行为。而且,可以显式地设置某个主机为默认虚拟主机,即在"listen"指令中设置"default_server"参数:
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
"default_server"参数从0.8.21版开始可用。在之前的版本中,应该使用"default"参数代替。
请注意"default_server"是监听端口的属性,而不是主机名的属性。后面会对此有更多介绍。
二、server的解析
- ngx_http_add_listen
listen字段解析的主回调函数。 - ngx_http_add_addresses
端口(ngx_http_conf_port_t)已存在,地址和虚拟主机不确定是否存在时,调用该接口为ngx_http_conf_port_t加入一个新的地址。 - ngx_http_add_address
端口(ngx_http_conf_port_t)已存在,地址不存在时,调用该接口为ngx_http_conf_port_t加入一个新的地址。 - ngx_http_add_server
端口和地址均已存在,调用该接口为ngx_http_conf_addr_t加入新的虚拟主机。
ngx_http_conf_addr_t->opt
即ngx_http_listen_opt_t,根据配置文件中listen参数,对套接字选项进行保存。
三、形成散列表
对每一个ngx_http_conf_addr_t(即每地址),都会形成一个散列表,用于查找该ip:port上建立连接所对应的server块。
HASH表
以ngx_http_server_name_t中的name为key,*server为value,建立hash表,hash表保存在ngx_http_conf_addr_t中的hash、*wc_head、*wc_tail字段。
四、形成监听(ngx_listening_t)
对于每一个ngx_http_conf_port_t,都需要形成一个或多个监听(存在通配符时是一个,不存在通配符是多个),
server查询
当某个监听套接字触发后,唯一的ngx_http_port_t确定。如果监听非通配符,则为一个的ngx_http_in_addr_t也唯一确定;如果监听通配符,则需要通过套接字选项获取客户真正访问的地址,之后查询ngx_http_port_t->addrs,确定对应的地址节点(ngx_http_in_addr_t)。
for (i = 0; i < port->naddrs - 1; i++) {
if (addr[i].addr == sin->sin_addr.s_addr) {
break;
}
}
hc->addr_conf = &addr[i].conf;
之后根据报文中携带的host信息,查询该ngx_http_in_addr_t的hash表,从而获取server块(ngx_http_core_srv_conf_t)。
ls->servers:这个监听地址包含的所有虚拟主机。
typedef struct {
/* ngx_http_in_addr_t or ngx_http_in6_addr_t */
void *addrs; //所有地址信息,通配符情况时包含多个,无通配符包含一个
ngx_uint_t naddrs; //通配符情况下表示包含的地址数,无通配符时为1
} ngx_http_port_t;
typedef struct {
in_addr_t addr; //具体地址
ngx_http_addr_conf_t conf;
} ngx_http_in_addr_t;
struct ngx_http_addr_conf_s {
/* the default server configuration for this address:port */
ngx_http_core_srv_conf_t *default_server; //默认的server块
ngx_http_virtual_names_t *virtual_names; //包含该地址下所有虚拟主机name和server块结构体的hash表。
unsigned ssl:1;
unsigned http2:1;
unsigned proxy_protocol:1;
};