ngx_http_update_location_config
1 定义
ngx_http_update_location_config 函数 定义在 src/http/ngx_http_core_module.c2 作用
ngx_http_update_location_config 函数的作用是 将请求已匹配到的 location 配置应用到请求对象 `r` 上, 使其在运行时生效。3 详解
1 函数签名
voidngx_http_update_location_config(ngx_http_request_t*r)1. 返回值类型 void
函数不返回任何值,调用者无法获得操作成功与否的直接反馈。
2. 函数名 ngx_http_update_location_config
ngx_http_:
表明该函数属于 HTTP 核心模块,处理的是 HTTP 协议相关的逻辑。
update:
动词,准确地描述了函数的行为——“更新”。
它不是“创建”或“初始化”,而是将已经确定的 location 配置刷新到请求的运行时状态中。
这种更新可能发生多次,比如在内部重定向后重新匹配 location 时会再次调用。
location_config:
宾语,指明了更新的对象是“location 配置”。
在 Nginx 中,一个请求在通过FIND_CONFIG阶段匹配到具体的 location 块后,
就获得了该块下所有模块的配置集合,
本函数负责把这些静态配置转化为请求动态运行时的参数。
整体语义:
该函数是连接“静态 location 配置”与“动态请求处理”的桥梁。
每当请求匹配到一个新的 location,
都需要调用此函数将对应的配置参数 应用到请求对象上,
确保后续处理严格遵循该 location 的指令。
3. 参数ngx_http_request_t *r
指向 当前请求的 上下文结构体
2 逻辑流程
1 获取配置 2 更新各个配置 2-1 方法限制 2-2 更新连接错误日志(仅主请求) 2-3 配置 sendfile 2-4 请求体文件存储 2-5 设置请求体单缓冲区标志 2-6 Keep-Alive 2-7 配置 TCP_NOPUSH 2-8 设置内容处理器1 获取配置
{ngx_http_core_loc_conf_t*clcf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);2 更新各配置
2-1 方法限制
if(r->method&clcf->limit_except){r->loc_conf=clcf->limit_except_loc_conf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);}r->method是当前 HTTP 请求的方法,它以位掩码的形式存储
limit_except字段也是一个位掩码,记录着被limit_except指令禁止的方法集合。
r->method & clcf->limit_except是按位与操作。
如果结果非零,说明当前请求的 HTTP 方法恰好属于被限制的方法之一,条件成立。
r->loc_conf = clcf->limit_except_loc_conf;
clcf->limit_except_loc_conf是limit_except指令块内部的独立配置数组指针。
这个配置数组包含了limit_except块内所有指令
(如 allow、deny、以及可能嵌套的其他模块指令)所对应的模块配置。
这行赋值语句的作用是:
将请求的配置上下文整体切换为limit_except块内部的配置。
这意味着,从此刻起,所有后续模块看到的配置都将是limit_except块内部定义的规则,
而不是原 location 块的规则。
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
由于r->loc_conf刚刚被替换成了新的配置数组,
原先的 clcf 指针现在可能已经不指向当前生效的核心模块配置了
(因为配置数组已经改变)。
根据请求当前最新的r->loc_conf,重新取出 HTTP 核心模块在 location 级别的配置,
并将这个新的指针赋值给 clcf。
这样做是为了保证后续代码使用的是limit_except块内部可能重新定义的核心配置。
如果不更新 clcf,后续代码将继续读取原 location 的核心配置,这可能导致行为与预期不符。
2-2 更新连接错误日志(仅主请求)
if(r==r->main){ngx_set_connection_log(r->connection,clcf->error_log);}2-3 配置 sendfile
if((ngx_io.flags&NGX_IO_SENDFILE)&&clcf->sendfile){r->connection->sendfile=1;}else{r->connection->sendfile=0;}据操作系统能力和当前 location 的配置,
决定是否为该连接启用 sendfile 功能。
2-4 请求体文件存储
if(clcf->client_body_in_file_only){r->request_body_in_file_only=1;r->request_body_in_persistent_file=1;r->request_body_in_clean_file=clcf->client_body_in_file_only==NGX_HTTP_REQUEST_BODY_FILE_CLEAN;r->request_body_file_log_level=NGX_LOG_NOTICE;}else{r->request_body_file_log_level=NGX_LOG_WARN;}根据 location 的配置,
设置请求对象中关于“客户端请求体文件存储”的相关标志和日志级别
2-5 设置请求体单缓冲区标志
r->request_body_in_single_buf=clcf->client_body_in_single_buffer;用于控制后续读取客户端请求体时的内存缓冲策略。
2-6 Keep-Alive
if(r->keepalive){只有当r->keepalive当前为 1(即初步允许长连接)时,
才进入该代码块进行更细致的检查。
如果基础条件就不满足(例如客户端明确要求 Connection: close),
后续检查就没有必要,直接跳过。
if(clcf->keepalive_timeout==0){r->keepalive=0;keepalive_timeout对应指令keepalive_timeout的第一个参数。
该指令控制服务器在长连接上等待下一个请求的空闲超时时间(单位秒,内部转换为毫秒)。
当该值被显式设置为 0 时,表示完全禁用长连接。
因此,如果 location 配置了 keepalive_timeout 0;,
那么无论客户端如何请求,服务器都会在本次响应后关闭连接。
动作:
将 r->keepalive 置为 0,本函数后面不再重新设置它,后续的连接管理逻辑会据此关闭连接。
}elseif(r->connection->requests>=clcf->keepalive_requests){r->keepalive=0;r->connection->requests记录了当前连接上已经处理过的请求总数。
每完成一个请求,该计数就会增加。
clcf->keepalive_requests对应指令keepalive_requests,
指定了单个长连接上允许处理的最大请求数。
达到该数量后,服务器会主动关闭连接,强制客户端重新建立连接,以平衡负载和资源。
比较:如果已处理的请求数已经达到或超过了配置的上限,则强制关闭长连接。
设计意义:
防止单个连接处理过多请求,确保连接能够被及时回收,
避免一个连接长时间占用服务器资源。
}elseif(ngx_current_msec-r->connection->start_time>clcf->keepalive_time){r->keepalive=0;ngx_current_msec:
Nginx 缓存的当前时间,单位毫秒。
r->connection->start_time:
连接建立时的起始时间(毫秒戳)。
clcf->keepalive_time
对应指令keepalive_time,
指定了一个长连接从建立开始所允许的最大存活时间(毫秒)。
计算:
当前时间减去连接建立时间,即为连接已经存活的总时长。
如果超过了keepalive_time,则关闭长连接。
设计意义:
限制连接的总生命周期,避免连接因频繁复用而长期不释放,
有助于平滑升级或资源回收
}elseif(r->headers_in.msie6&&r->method==NGX_HTTP_POST&&(clcf->keepalive_disable&NGX_HTTP_KEEPALIVE_DISABLE_MSIE6)){/* * MSIE may wait for some time if an response for * a POST request was sent over a keepalive connection */r->keepalive=0;检查是否对 MSIE 6 禁用 Keep-Alive
r->headers_in.msie6:
一个请求标志,当 User-Agent 头部表明客户端是旧版 MSIE 6 时被设置为 1。
这些旧版本浏览器在处理 Keep-Alive 时存在已知问题。
}elseif(r->headers_in.safari&&(clcf->keepalive_disable&NGX_HTTP_KEEPALIVE_DISABLE_SAFARI)){/* * Safari may send a POST request to a closed keepalive * connection and may stall for some time, see * https://bugs.webkit.org/show_bug.cgi?id=5760 */r->keepalive=0;}}检查是否对 Safari 禁用 Keep-Alive
2-7 配置 TCP_NOPUSH
if(!clcf->tcp_nopush){/* disable TCP_NOPUSH/TCP_CORK use */r->connection->tcp_nopush=NGX_TCP_NOPUSH_DISABLED;}clcf->tcp_nopush就是tcp_nopush指令的值:
如果配置了tcp_nopush on;,它为非零值;
如果是tcp_nopush off;或者没配置,它通常为 0。
r->connection->tcp_nopush
这个字段位于连接对象上,而不是请求对象。
它表示当前连接是否启用 TCP 层面的推送优化。
Nginx 在发送静态文件时,会调用操作系统提供的选项,
先将数据攒起来,等数据块足够大后再一起发送,
这样可以减少网络上小包的数量,提高传输效率。
NGX_TCP_NOPUSH_DISABLED
这是一个 Nginx 内部定义的特殊常量,
表示“明确禁用TCP_NOPUSH/TCP_CORK”。
把它赋给r->connection->tcp_nopush,就相当于告诉后续的发送逻辑:
不要使用这个优化,数据应该尽快发送,不要故意延迟等待更多数据。
2-8 设置内容处理器
if(clcf->handler){r->content_handler=clcf->handler;}}把当前 location 指定的“内容处理器”绑定到请求对象上。
