ngx_http_send_header
1 定义
ngx_http_send_header 函数
定义在
./nginx-1.24.0/src/http/ngx_http_core_module.c
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
{
if (r->post_action) {
return NGX_OK;
}
if (r->header_sent) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"header already sent");
return NGX_ERROR;
}
if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
}
return ngx_http_top_header_filter(r);
}
2 目的
1. 核心设计目的
`ngx_http_send_header` 是 Nginx HTTP 框架中 发送响应头的统一入口。
它的设计目的可以归纳为三点:
1. 提供一个唯一且安全的发送起点:
确保在整个 Nginx 系统中,响应头的实际发送动作只从这一个地方开始,
防止各个模块擅自发送头部而导致混乱。
2. 执行发送前的必要检查与修正:
在数据流出前,统一处理几项全局性的前置条件,
如“是否还需要发送”、“状态码是否需要覆盖”等。
3. 将响应头推入过滤器链:
调用 `ngx_http_top_header_filter`,
启动由各个模块串起来的“头部过滤链”。
这条链可以对即将发送的头部做最后的修改、压缩或序列化,
然后通过操作系统网络接口发送出去。
2. 它在整体流程中的角色
`ngx_http_send_header` 的设计意图可以概括为:
在请求处理的“内容生成阶段”结束后,作为从“准备响应头”过渡到“网络发送”的闸门。
它依次完成了:
- 检查是否应该跳过(post_action)
- 检查是否已经发送过(防止重复)
- 最终确定 HTTP 状态码(err_status 覆盖)
- 启动过滤器链(让所有模块完成最后的处理并发送)
因此,它是 Nginx 保证响应头正确、安全、且只发送一次的关键机制,
也是模块化处理 HTTP 头部的基础。
3 详解
1 函数签名
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
1. 返回值类型:`ngx_int_t`
用于表示函数的执行状态。
这个函数返回一个整数值,用来告诉调用者操作的结果。可能的返回值包括:
NGX_OK:成功。
可能是头部已经发送成功,也可能因为特殊情况(如 post_action 请求)而无需发送。
NGX_ERROR:
错误。例如,检测到头部已经被重复发送,或者底层发送操作失败。
调用者通过检查返回值是否为 NGX_OK 来判断函数是否正常完成。
2. 函数名:ngx_http_send_header
函数名由下划线分隔的多个部分组成,遵循 Nginx 的命名惯例:
ngx:全局前缀,表明这是 Nginx 源码的一部分,用于避免命名冲突。
http:表明该函数属于 HTTP 模块子系统,处理 HTTP 协议相关的逻辑。
send:动词,意为“发送”。这里指将数据通过网络连接传输给客户端。
header:名词,指 HTTP 响应中的头部部分(响应行和各个头部字段)。
因此,ngx_http_send_header 的完整含义是:
在 HTTP 模块中,将准备好的响应头发送给客户端的函数。
3. 参数列表:(ngx_http_request_t *r)
参数类型 ngx_http_request_t *:
ngx_http_request_t 是一个结构体类型,包含了处理一个 HTTP 请求所需的所有信息:
请求行、请求头部、将要发送的响应头部(r->headers_out)、客户端连接、
各种状态标志(如 header_sent、err_status)等。
4. 签名整体反映出的设计信息
功能直接:函数名明确指出了“发送头部”这个动作,没有歧义。
依赖请求上下文:
函数所需的一切都来自 r 参数(状态标志、响应头内容、底层连接),
不依赖外部全局变量。这使得函数的行为完全由请求状态决定,安全且可预测。
返回状态:
通过返回 NGX_OK 或 NGX_ERROR 来报告操作结果,
与 Nginx 整体的错误处理风格一致。
2 逻辑流程
1. 特殊请求跳过:
如果是 post_action 子请求,不需要发送任何头部,直接返回成功。
2. 重复发送防护:
如果头部已经被发送过,记录告警日志并返回错误,避免协议违规。
3. 错误状态码覆盖:
如果在处理过程中产生了错误状态码(err_status),则覆盖原有的响应状态码,
并清空自定义状态行,保证错误响应的一致性和正确性。
4. 启动过滤器链:
调用 ngx_http_top_header_filter(r),将控制权交给过滤器链,
由各个模块完成最终的头部处理、序列化和网络发送。
1. 特殊请求跳过
{
if (r->post_action) {
return NGX_OK;
}
检查是否为 post_action 请求
r->post_action 是请求结构体中的一个标志字段。
当 Nginx 配置了 post_action 指令时,
主请求完成后会触发一个内部子请求,
这个子请求的 post_action 字段为非零值。
作用:判断当前请求是否是一个“后置动作”子请求。
对于 post_action 子请求,
它的目的仅仅是在后台执行某个操作(比如记录日志),
不需要向客户端返回任何数据,包括响应头。
因此,函数直接返回 NGX_OK 表示“成功,无事发生”。
意义:避免向客户端错误地发送多余的响应头,确保 post_action 请求完全静默。
2. 重复发送防护
if (r->header_sent) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"header already sent");
return NGX_ERROR;
}
检查是否已经发送过响应头r->header_sent 是请求结构体中的一个整数标志。
当响应头已经被发送过一次后,这个标志会被设置为 1。
作用:检测是否有重复发送头部的尝试。
记录错误日志
返回错误状态
3. 错误状态码覆盖
if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
}
检查是否有错误状态码需要覆盖r->err_status 是请求结构体中的一个整数字段。
Nginx 在处理请求的任何阶段如果遇到错误,
可以设置这个字段(例如 403、500 等 HTTP 状态码)。
如果请求正常完成,该字段为 0。
作用:判断在最终发送前,是否需要用错误状态码替换当前响应头中的状态码。
保证错误的优先级最高,无论之前流程如何设置,最终都以错误状态码为准
清空自定义状态行
当错误状态码覆盖后,自定义的状态行可能不再匹配
(例如原本为 200 OK 设置的文本,对于 500 是无意义的),
清空它让 Nginx 为错误状态码生成正确的标准文本。
4. 启动过滤器链
return ngx_http_top_header_filter(r);
}
启动头部过滤器链并返回结果
ngx_http_top_header_filter 是一个函数指针,
指向 Nginx 头部过滤器链的第一个过滤器函数。
Nginx 的过滤器链机制允许各个模块(如 gzip、charset、not_modified 等)
注册自己的头部处理函数,这些函数首尾相连形成一条链。
调用 ngx_http_top_header_filter(r) 会依次执行链中的所有头部过滤函数,
完成对响应头的最后修改、序列化,并最终通过操作系统调用(如 write)发送到网络。
作用:
真正执行“发送响应头”动作的是这条过滤器链,
这个调用将请求对象传入链中,让整个链条运转起来。
return 将过滤链的返回值直接作为本函数的返回值。
如果过滤链执行成功,最终会返回 NGX_OK;
如果发送过程中出现错误,则返回 NGX_ERROR
ngx_http_not_modified_header_filter
ngx_http_charset_header_filter
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)