首先先看一个图:
上图是nginx listen端口配置形成一个结构图,有几点需要提醒一下:
1. 每个端口会有一个ngx_http_port_t结构,相同端口配置会ngx_http_conf_addr_t结构存放到addrs变量中。
2. 并不是所有相同端口都要创建ngx_http_conf_addr_t,当出现listen addr:port配置时,如果addr跟之前
同一port配置也相同时,则不创建该结构,只是将该port所在的server conf,即cscf放到ngx_http_conf_addr_t结构的servers
数组中。若addr部分不同,也会创建一个新的ngx_http_conf_addr_t。
在所有解析完配置后,ngx_http_optimize_servers会做一些整理优化工作,最重要的是为后面开启端口监听做准备。
对于每个port,会调用ngx_http_init_listening:
static ngx_int_t
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
{
ngx_uint_t i, last, bind_wildcard;
ngx_listening_t *ls;
ngx_http_port_t *hport;
ngx_http_conf_addr_t *addr;
addr = port->addrs.elts;
last = port->addrs.nelts;
// 同一个端口的配置,即 ngx_http_conf_addr_t会有作排序操作,下面的注释做了介绍
// listen的配置还有不少细节,可以参考官方wiki: http:nginx.org/HttpCoreModule#listen
/*
* If there is a binding to an "*:port" then we need to bind() to
* the "*:port" only and ignore other implicit bindings. The bindings
* have been already sorted: explicit bindings are on the start, then
* implicit bindings go, and wildcard binding is in the end.
*/
// 查看该端口的配置里面有个出现通配情况的
if (addr[last - 1].opt.wildcard) {
// 只把最后一个通配的设置为bind,这样前面的通配不具有bind标记
// 对于bind的标记,典型的情况(已排序好的)是 :binded,nobind,wildcard(nobind),wildcard(binded)
addr[last - 1].opt.bind = 1;
bind_wildcard = 1;
} else {
bind_wildcard = 0;
}
i = 0;
while (i < last) {
// 除了有通配的配置之外,还存在明确指出需要bind的配置,需要处理该配置
// 什么情况下是明确指出要bind的,可参考函数ngx_http_core_listen
if (bind_wildcard && !addr[i].opt.bind) {
i++;
continue;
}
// 需要监听的port,分配一个ngx_listening_t结构
ls = ngx_http_add_listening(cf, &addr[i]);
if (ls == NULL) {
return NGX_ERROR;
}
hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
if (hport == NULL) {
return NGX_ERROR;
}
ls->servers = hport;
if (i == last - 1) {
// 到这里,就到了处理该结束的时候了,当last > 1意味着配置中存在nobind和
// wildcard的类型,即此时该端口被看做对应多个地址,对于这中情况的处理可以参考ngx_http_init_request
hport->naddrs = last;
} else {
// 当前port为明确需要bind的,naddrs为1的含义是该port被明确bind到某个地址
hport->naddrs = 1;
// 下面addr++,从下一面port继续处理,即相对与addr来说,数组下边自然是从0开始啦
i = 0;
}
switch (ls->sockaddr->sa_family) {
default: /* AF_INET */
if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
return NGX_ERROR;
}
break;
}
// 一旦某个标记为bind的端口处理完,addr就从下一个开始
addr++;
// 从下一个addr开始到结束的port个数
last--;
}
return NGX_OK;
}
然后我们看ngx_http_init_request函数:
if (port->naddrs > 1) {
// naddrs > 1的情况前面已经分析过了,最终要使用哪个地址,就通过ngx_connection_local_sockaddr
// 来处理了。
/*
* there are several addresses on this port and one of them
* is an "*:port" wildcard so getsockname() in ngx_http_server_addr()
* is required to determine a server address
*/
// 通过这个函数,实质上就是调用了getsockname,获得该连接的服务器端ip
if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
switch (c->local_sockaddr->sa_family) {
default: /* AF_INET */
sin = (struct sockaddr_in *) c->local_sockaddr;
addr = port->addrs;
/* the last address is "*" */
// 如果与该port上其他非binded的某个配置,具有相同的ip,就是用它的配置,否则就用最后这个的配置
for (i = 0; i < port->naddrs - 1; i++) {
if (addr[i].addr == sin->sin_addr.s_addr) {
break;
}
}
addr_conf = &addr[i].conf;
break;
}
} else {
// naddrs == 1
switch (c->local_sockaddr->sa_family) {
default: /* AF_INET */
addr = port->addrs;
addr_conf = &addr[0].conf;
break;
}
}
// 上面的操作最主要的作用就是拿到cscf,即核心的server conf,ngx_http_core_srv_conf_t结构。
// 关于default_server,在ngx_http_add_address处理,第一次添加的port会设置default_server
// 为该port的当前cscf,同时在ngx_http_add_addresses中会针对相同addr:port的,修改一下
// default_server的指向,具体可以参考该函数。
cscf = addr_conf->default_server;
// 得到了cscf,剩下的就好说了。这样发往该端口的请求,它的相关配置就得到了,
r->main_conf = cscf->ctx->main_conf;
r->srv_conf = cscf->ctx->srv_conf;
r->loc_conf = cscf->ctx->loc_conf;
在处理请求时,相关模块的配置通常通过一些宏来获得:
#define ngx_http_get_module_main_conf(r, module) (r)->main_conf[module.ctx_index]
#define ngx_http_get_module_srv_conf(r, module) (r)->srv_conf[module.ctx_index]
#define ngx_http_get_module_loc_conf(r, module) (r)->loc_conf[module.ctx_index]
需要注意的是,这里获得配置都是http core的,特别是对于location的配置,不同的模块可能有自己的需求,所以才有了http处理阶段中NGX_HTTP_FIND_CONFIG_PHASE的出现,这个阶段的主要作用就是为了根据具体的url,在核心location配置中的static_locations及regex_locations来查找相应location的配置。具体地,可以参考ngx_http_core_find_location。在看这个之前,需要的了解的是nginx
location三叉树的结构。普通的location,一般指非正则的,都是放在static_locations管理的三叉树里,正则的配置则放到regex_locations链表里。明确了这些概念之后,函数的逻辑就很简单了。
<!--192.168.1.237-->
分享到:
相关推荐
简单梳理一下nginx中关于server 和location的配置. 比如URL:www.mask_dev2.com:9999/login/ server管的前半部分,即:www.mask_dev2.com:9999 location管的是后半部分,即:/login/ 一个nginx可以配置多个...
nginx 配置跨域不生效 如下配置 server { listen 80; server_name localhost; # 接口转发 location /api/ { # 允许请求地址跨域 * 做为通配符 add_header 'Access-Control-Allow-Origin' '*'; # 设置请求...
Nginx在决定请求由哪个server块执行时,主要关注的是server块中的listen和server_name两个字段 listen指令 listen字段定义server响应的ip和端口,如果没有明确配置listen字段,默认监听0.0.0.0:80(root)或者0.0.0.0:...
•location 是在 server 块中配置,用来通过匹配接收的uri来实现分类处理不同的请求,如反向代理,取静态文件等 •location 在 server 块中可以有多个,且是有顺序的,会被第一个匹配的 location 处理 •localtion ...
├─2.13 Nginx进阶基础-常见配置-location.mp4 ├─3.01 Nginx进阶配置提升-预定义变量及日志详解.mp4 ├─3.02 Nginx进阶配置提升-日志切割及升级.mp4 ├─3.03 Nginx进阶-配置提升-Nginx错误页面.mp4 ├─3.04 ...
本文主要介绍了nginx 多个location转发任意请求或访问静态资源文件的实现,分享给大家,具体如下: server { #监听的端口 listen 80; #监听的域名 server_name localhost; #监听带后缀的url location ^~\.txt...
location /NginxStatus { stub_status on; access_log on; auth_basic "NginxStatus"; auth_basic_user_file conf/htpasswd; } #禁止访问 .htxxx 文件 location ~ /\.ht { deny all; } } }
Nginx做前端代理,当用户请求服务时,可以根据url进行判断,然后分配到不同的后台webserver上。 1.2 Nginx的负载均衡实现原理:首先在http模块中配置使用upstream模块定义后台的web server的池子,名为proxy-web,在...
Nginx中的server_name指令主要用于配置基于名称虚拟主机,server_name指令在接到请求后的匹配顺序分别为: 1、准确的server_name匹配,例如: server { listen 80; server_name ssdr.info www.ssdr.info; ... } 2...
Nginx配置 # HTTPS server # server { listen 443 ssl; server_name your.domain.name; ... location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $Host; proxy_set_header X-Real-I
最近一个项目需要承载高并发请求,所以在后端语言上选择了NodeJs,但是nodejs有时候读取不到请求的主机名,所以想到使用nginx+nodejs的方式进行处理。 Nginx 配置 代码如下 upstream io_nodes { server ...
nginx 在收到一条请求时将先通过 server_name 匹配一个 server, 然后使用 server 中的 location 继续匹配. 匹配 server_name 在 nginx 中, server_name 决定了当收到一个请求后哪一个 server 会被使用. nginx 会...
使用nginx做反向代理的时候,可以简单的直接把请求原封不动的转发给下一个服务。设置proxy_pass请求只会替换域名,如果要根据不同的url后缀来访问不同的服务,则需要通过如下方法: 方法一:加”/” server { ...
nginx配置文件的详细介绍。 #设定http服务器 #server表示虚拟主机可以理解为一个站点,可以配置多个server节点搭建多个站点 #每一个请求进来确定使用哪个server由server_name确定 #location用来匹配同一域名下...
nginx_limit_access_module - 可通过指定的 HTTP POST 接口中的值来拒绝请求。 示例配置: http { limit_access_zone zone=one:5m bucket_number=10007 type=ip; server { listen 80; server_name ...
root与alias主要区别在于nginx如何解释location后面的uri,这会使两者分别以不同的方式将请求映射到服务器文件上。 [root] 语法:root path 默认值:root html 配置段:http、server、location、if [alias] 语法:...
轮询即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器。 配置的例子如下: http{ upstream sampleapp { server <<dns>>; server <<another>>; } .... server{ ...
nginx和tomcat负载均衡 比如 www.csdn.NET 网站后面有 2个tomcat。 配置负载均衡: upstream csdn-tomcat{ server 192.168.100.101:8080; server 192.168.100.102:8080; } server { listen 80; server_name ...