1 定义 ngx_http_read_request_header 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.cstatic ssize_t ngx_http_read_request_header ( ngx_http_request_t * r) { ssize_t n; ngx_event_t * rev; ngx_connection_t * c; ngx_http_core_srv_conf_t * cscf; c= r-> connection; rev= c-> read; n= r-> header_in-> last- r-> header_in-> pos; if ( n> 0 ) { return n; } if ( rev-> ready) { n= c-> recv ( c, r-> header_in-> last, r-> header_in-> end- r-> header_in-> last) ; } else { n= NGX_AGAIN; } if ( n== NGX_AGAIN) { if ( ! rev-> timer_set) { cscf= ngx_http_get_module_srv_conf ( r, ngx_http_core_module) ; ngx_add_timer ( rev, cscf-> client_header_timeout) ; } if ( ngx_handle_read_event ( rev, 0 ) != NGX_OK) { ngx_http_close_request ( r, NGX_HTTP_INTERNAL_SERVER_ERROR) ; return NGX_ERROR; } return NGX_AGAIN; } if ( n== 0 ) { ngx_log_error ( NGX_LOG_INFO, c-> log, 0 , "client prematurely closed connection" ) ; } if ( n== 0 || n== NGX_ERROR) { c-> error= 1 ; c-> log-> action= "reading client request headers" ; ngx_http_finalize_request ( r, NGX_HTTP_BAD_REQUEST) ; return NGX_ERROR; } r-> header_in-> last+= n; return n; } ngx_http_read_request_header 函数的主要作用是 以非阻塞方式从客户端连接读取 HTTP 请求头原始数据。 它优先检查接收缓冲区中是否已有未处理的数据并直接返回其长度; 若无数据且读事件就绪则执行系统调用读入新数据; 若读操作尚未就绪,则设置客户端请求头超时定时器并注册读事件, 然后向上层返回 `NGX_AGAIN` 等待下次被触发; 当读取到数据时更新缓冲区指针并返回字节数, 若遇到连接关闭或读取错误则记录日志并以 400 错误结束请求。2 详解 1 函数签名 static ssize_t ngx_http_read_request_header ( ngx_http_request_t * r) 返回值 正数 > 0:成功读取的字节数(或缓冲区中已有的未处理数据长度), 调用者可据此继续解析请求头。 NGX_AGAIN(通常为 -2): 表示操作尚未完成, 没有数据可读,需要等待 I/O 事件就绪后再次调用。 NGX_ERROR(通常为 -1): 发生严重错误(如读取失败、连接关闭),请求已终结。参数 ngx_http_request_t *r 当前 请求对象2 逻辑流程 1 局部变量 2 未处理数据 3 读取数据 3-1 暂无数据 3-2 读取出错 4 更新缓冲区指针并返回1 局部变量{ ssize_t n; ngx_event_t * rev; ngx_connection_t * c; ngx_http_core_srv_conf_t * cscf; c= r-> connection; rev= c-> read; 2 未处理数据n= r-> header_in-> last- r-> header_in-> pos; if ( n> 0 ) { return n; } #1 header_in 是专门用于接收 HTTP 请求头的缓冲区 pos:指向待解析数据的起始位置。 last:指向已读入数据的末尾。 end:指向缓冲区容量的末尾。 计算 n 为缓冲区中尚未解析的字节数。 意义:Nginx 采用边读边解析模式。 每次进入此函数可能是新一轮读事件触发, 但有可能上一次 recv 读入的数据尚未被解析完 此时无需执行系统调用,直接返回已有长度,让上层解析器继续工作。#2 若已有数据则直接返回3 读取数据if ( rev-> ready) { n= c-> recv ( c, r-> header_in-> last, r-> header_in-> end- r-> header_in-> last) ; } else { n= NGX_AGAIN; } #1 rev->ready 读事件已就绪 读取数据#2 未就绪, 无数据可读 直接设 n = NGX_AGAIN 表示暂时无数据,需等待事件通知3-1 暂无数据if ( n== NGX_AGAIN) { if ( ! rev-> timer_set) { cscf= ngx_http_get_module_srv_conf ( r, ngx_http_core_module) ; ngx_add_timer ( rev, cscf-> client_header_timeout) ; } if ( ngx_handle_read_event ( rev, 0 ) != NGX_OK) { ngx_http_close_request ( r, NGX_HTTP_INTERNAL_SERVER_ERROR) ; return NGX_ERROR; } return NGX_AGAIN; } #1 暂无数据可读 设置读取超时定时器 !rev->timer_set:检查该读事件是否已经设置过定时器 未设置,则设置定时器#2 注册读事件 失败, 直接关闭请求并记录 500 错误 返回 NGX_ERROR 结束函数 确保事件在监控中,这样下次收到数据才能收到通知然后去处理#3 返回 NGX_AGAIN 告诉调用链:数据尚未读取完毕,等待事件3-2 读取出错if ( n== 0 ) { ngx_log_error ( NGX_LOG_INFO, c-> log, 0 , "client prematurely closed connection" ) ; } n == 0 表示客户端关闭了连接 记录一条 INFO 级别日志,内容为“客户端过早关闭连接”if ( n== 0 || n== NGX_ERROR) { c-> error= 1 ; c-> log-> action= "reading client request headers" ; ngx_http_finalize_request ( r, NGX_HTTP_BAD_REQUEST) ; return NGX_ERROR; } 错误处理 标记连接发生错误 结束当前请求,传递状态码 400 Bad Request 返回 NGX_ERROR,终止函数4 更新缓冲区指针并返回r-> header_in-> last+= n; return n; } 成功读取了 n 个字节到缓冲区中 将缓冲区描述指针 last 向后移动 n 个字节,准确标记已填充数据的末尾 返回成功读取的字节数