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_headers_filter

ngx_http_userid_filter

ngx_http_charset_header_filter

ngx_http_ssi_header_filter

ngx_http_gzip_header_filter

ngx_http_range_header_filter

ngx_http_chunked_header_filter

ngx_http_header_filter

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐