ngx_http_send_header是Nginx中发送HTTP响应首部的关键函数,需在content阶段前正确设置r->headers_out.status、content_length_n、content_type等字段,且只能调用一次;它不直接发数据,须配合ngx_http_output_filter才能完成响应。

在 Nginx 模块开发中,ngx_http_send_header 是发送 HTTP 响应首部的关键函数,它标志着响应正式开始,后续调用 ngx_http_output_filter 才能将响应体写入连接。用错时机或忽略前置条件,会导致 500 错误、首部重复、或响应卡死。
必须先设置好 r->headers_out 成员
该函数不接受参数,只读取当前请求结构 r 中的 headers_out 字段。因此,在调用前务必完成以下设置:
-
状态码:赋值
r->headers_out.status = NGX_HTTP_OK;(默认是 0,会触发内部错误) -
Content-Length:若已知响应体长度,设
r->headers_out.content_length_n = len;;若为 chunked,则设为 -1 并确保r->chunked = 1; -
Content-Type:通过
r->headers_out.content_type_len和r->headers_out.content_type.data设置,例如ngx_string("text/plain") -
其他首部:如
Set-Cookie、X-My-Header,需用ngx_list_push(&r->headers_out.headers)添加,并正确初始化ngx_table_elt_t的key、value、hash
只能调用一次,且不可逆
ngx_http_send_header 内部会将 r->header_sent 置为 1,并清空部分 header 缓存。再次调用会直接返回 NGX_ERROR,Nginx 日志中出现 header already sent 即源于此。
常见误用场景:
- 在 rewrite 阶段或 access 阶段提前调用(此时尚未进入 content 阶段,
r->main->count可能异常) - 在子请求(subrequest)中误调主请求的
send_header - 异常分支中未加保护,导致成功和失败路径都执行了该函数
配合 output_filter 才能发出完整响应
仅调用 ngx_http_send_header 不会真正发送数据到 socket。它只是构造并缓存首部,等待后续的输出链(output chain)驱动。典型流程是:
- 填充
r->headers_out - 调用
ngx_http_send_header(r) - 构造
ngx_chain_t链表,指向响应体 buffer - 调用
ngx_http_output_filter(r, out)
如果跳过第三、四步,客户端只会收到一个空响应(HTTP 状态行 + CRLF),连接可能保持打开,浏览器显示空白或超时。
注意与 ngx_http_finalize_request 的协作
当模块决定终止请求(如返回 403 或重定向),不应在发送首部后直接 return,而应调用 ngx_http_finalize_request(r, rc),其中 rc 是状态码(如 NGX_HTTP_FORBIDDEN)。否则 Nginx 无法正确清理资源,可能导致 worker 进程卡住或内存泄漏。
特别地,若你在 handler 中返回 NGX_OK 但未发送响应,Nginx 会尝试 fallback 到默认处理,结果往往不符合预期。

















