内容概述
ngx_http_request.c
: 实现了 HTTP 请求的主要处理逻辑。ngx_http_request.h
: 定义了 HTTP 请求处理相关的数据结构和函数原型。ngx_http_request_body.c
: 处理 HTTP 请求体相关的逻辑。
新的HTTP请求到来时,处理流程分析
- 初始化请求:
- 新连接到来后,调用ngx_http_request函数初始化 ngx_http_request_t 结构
- 对连接信息进行整理,存储到请求结构用(目的为了后面处理的调用,对请求进行描述然后组织)
- 处理请求头
- ngx_http_process_requst函数,调用ngx_http_process_request_header处理请求头部
- 处理请求体
- 请求头处理完成后,调用ngx_http_process_request_body处理请求体,如果请求体需要读取数据,则调用ngx_http_read_request_body函数
- 根据请求方法调用相应函数
ngx_http_request.h
- 数据结构
- 该文件中包含有HTTP请求用到的主要数据结构
- 函数原型
- 声明用于处理HTTP请求的函数
- 宏定义
- 定义一些HTTP处理中常用的宏和常量
数据结构:ngx_http_request_t 存储HTTP请求的核心数据,其中有请求的所有信息
typedef struct ngx_http_request_s {
// 请求方法,如 GET, POST 等
ngx_str_t method_name; method_name:请求方法的名称,例如 "GET
ngx_uint_t method; method:请求方法的枚举值
// 请求 URI
ngx_str_t uri; uri:请求的 URI
ngx_str_t args; args:URI 中的参数
ngx_str_t exten; exten:URI 中的扩展名
ngx_str_t unparsed_uri; unparsed_uri:未解析的 URI
// 请求头部相关
ngx_http_headers_in_t headers_in; headers_in:请求头部信息
ngx_http_headers_out_t headers_out; headers_out:响应头部信息
// 请求体相关
ngx_http_request_body_t *request_body; request_body:请求体信息
// 连接信息
ngx_connection_t *connection; connection:与该请求相关的连接信息
// 请求处理的当前阶段
ngx_uint_t phase_handler; phase_handler:当前请求处理的阶段
// 请求上下文
void *ctx; ctx:请求的上下文信息
// 请求的处理结果
ngx_int_t http_version; http_version:HTTP 版本
ngx_int_t response_status; response_status:响应状态码
// ... 其他字段
} ngx_http_request_t;
ngx_http_header_in_t 请求头部信息
ngx_http_headers_out_t 响应头部信息
HTTP方法定义
HTTP状态码
函数原型声明
- ngx_http_create_request:初始化 HTTP 请求。
- ngx_http_process_request:处理 HTTP 请求,包括请求头和请求体的处理。
- ngx_http_process_request_headers:解析和处理 HTTP 请求头部。
- ngx_http_process_request_body:处理 HTTP 请求体。
- ngx_http_read_request_body:读取 HTTP 请求体数据。
- ngx_http_finalize_request:完成 HTTP 请求的处理,发送响应。
函数逻辑总结
- 初始化请求:接收到新连接时候,调用ngx_http_create_request函数初始HTTP请求结构
- 处理请求头部:调用ngx_http_process_request_headers函数解析和处理HTTP请求头部,将解析结果存储到请求结构中
- 处理请求体:ngx_http_process_request_body函数读取并处理HTTP请求体数据
- 处理请求:根据请求的具体要求,调用相应的处理函数完成请求的处理
- 完成请求:调用ngx_http_finalize_request函数完成HTTP请求的处理,发送响应
ngx_http_request.c
- HTTP请求的初始化和处理:初始化HTTP请求、处理请求头、处理请求体等
- 方法处理器:不同阶段需要处理函数
主要功能分析(头部文件中声明的声明,此处简写)
- 初始化HTTP请求
- 处理请求头部
- 处理请求体
- 根据请求内容,完成具体请求
- 完成请求,发送具体响应
初始化请求代码分析
- 从连接的内存池中分配内存空间,创建一个新的ngx_http_request_t结构体
- 将新创建的请求结构和当前连接关联
- 初始化请求的基本属性(方法、URI 处理方法)
#include "ngx_http_request.h"
// 初始化 HTTP 请求
ngx_int_t ngx_http_create_request(ngx_connection_t *c) {
ngx_http_request_t *r;
// 为 ngx_http_request_t 结构分配内存
r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
if (r == NULL) {
return NGX_ERROR;
}
// 将请求结构体与连接关联
c->data = r;
// 初始化请求的方法名称
r->method_name.data = NULL;
r->method_name.len = 0;
// 初始化请求的 URI
r->uri.data = NULL;
r->uri.len = 0;
// 初始化请求的处理阶段
r->phase_handler = 0;
r->ctx = NULL;
return NGX_OK;
}
ngx_pcalloc函数从内存池分配内存,同时将内存初始化为0。此处Nginx使用的内存池分配空间的方法,而没有使用new等方法分配空间,具体原因参考下文。
请求结构体和连接关联,因为需要直到该请求是哪个连接发出的。
初始化请求的具体内容
r->method_name
: 用于存储 HTTP 请求的方法名称,例如 "GET" 或 "POST"。这里初始化为 NULL 和 0,表示尚未设置。r->uri
: 用于存储请求的 URI,同样初始化为 NULL 和 0。r->phase_handler
: 表示请求处理的当前阶段,初始化为 0。r->ctx
: 用于存储请求的上下文信息,初始化为 NULL
ngx_http_request_t结构分析(重点内容)
处理请求头代码分析
- ngx_http_process_request_headers:解析HTTP请求头部,请求行以及各个头部字段
- 解析请求行
- 调用
ngx_http_parse_request_line
函数解析请求行,并将解析结果存储到ngx_http_request_line_t
结构中。- 解析请求头部字段
- 使用
ngx_http_parse_header_line
函数解析每一个请求头部字段,并将解析结果存储到请求结构的headers_in
列表中。
处理请求体:ngx_http_process_request_body处理HTTP请求体的读取和解析
- 检查是否有请求体,如果没有请求体则直接返回
- 分配请求体缓冲区:从内存池中分配请求体缓冲区,并初始化该区域
- 读取请求体数据:使用ngx_http_read_request_body函数从连接中读取请求体数据
读取请求体数据:使用ngx_http_read_request_body,读取数据后将其存储到请求结构
ngx_http_do_read_client_request_body函数负责从连接中读取请求体的数据,并将其写入缓冲区
- 从连接中读取数据,使用recv方法读取数据到缓冲区中
- 更新缓冲区指针:更新缓冲区last指针的位置,指向数据结束的位置
- 判断数据是否读取完成:判断缓冲区是否满了,如果还没满则表明还要继续读取数据。
当有事件可读的时候,调用ngx_http_read_client_request_body_handler函数进行读取数据
- 获取连接和请求结构
- 继续读取数据,调用ngx_http_do_read_client_request_body函数继续读取数据
- 处理请求体数据:如果数据读取完成,则调用回调函数,对出具进行处理
处理请求行: 提取其方法、URI、HTTP版本
处理请求头: 解析请求头部的每个字段
ngx_http_request_line_t 结构分析
ngx_http_request_body.c
处理HTTP请求体:具体实现了读取和处理HTTP请求体的功能
- 初始化请求体处理
- 开辟空间存储请求体数据
- 调用ngx_http_process_request_body函数初始化请求体缓冲区,同时调用ngx_http_read_request_body开始读取请求体的数据
- 设置读事件处理函数
- ngx_http_read_request_body函数,设置读事件处理函数ngx_http_read_client_request_body_handler
- 读取请求体数据
- ngx_http_read_clietn_request_body_handler函数,从连接中读取请求体数据到缓冲区,同时更新缓冲区指针。
- 处理读事件
- 调用处理函数,开始对请求体进行读取数据
- 处理请求体数据
- 当请求体数据读取完成后,调用定义的回调函数进行处理请求体数据。
ngx_http_request_body函数用于读取HTTP请求体的数据,并将其存储到请求结构中
ngx_http_do_read_client_request_body函数从连接中读取请求体数据,并将其写入缓冲区
ngx_http_read_client_request_body_handler函数用于处理写事件,当有数据可读的时候,该函数被调用来读取数据
数据结构分析:ngx_http_request_body_t结构
数据结构分析:ngx_chain_t
数据结构分析:ngx_buf_t
知识点补充
内存池
内存池是一块预先分配号的区域,专门用来管理和分配小块内存。内存池通过减少内存分配和释放操作的次数,提高了内存管理的效率,同时减少内存碎片的产生。
内存池运行流程主要有以下几步。首先初始化,创建一个内存池,分配一块连续的大内存块。然后开始给向内存池申请的函数分配其所需要的内存。最后在合适的时候释放整个内存池,注意这里不是逐个释放创建的小块内存,而是释放整个内存。
内存池的主要优势
- 提高系统性能
- 减少系统调用:因为使用malloc或者new进行内存分配会涉及系统调用,而内存池在初始化的时候一次性分配了一大块内存,减少了系统调用次数。
- 快速分配和释放:从内存池中分配内存只需要移动指针,不需要复杂的内存管理操作。同时,释放内存池也只需要一次操作,效率更高。
- 减少内存碎片
- 连续分配:内存池分配的内存块是连续的,避免了内存碎片的问题
- 集中管理:内存池中的内存集中管理,释放的时候也是统一释放的,避免的内存碎片问题。
- 简化管理
Nginx管理线程池结构分析ngx_pool_t
last
: 指向内存池中当前可用内存的起始位置。end
: 指向内存池的末尾。next
: 指向下一个内存池(用于管理多个内存池)。large
: 管理大块内存。cleanup
: 清理函数列表。log
: 日志信息。
ngx_pcalloc分配并初始化内存的函数
ngx_palloc
:从内存池中分配指定大小的内存。ngx_memzero
:将分配的内存初始化为零。
Nginx下HTTP请求处理功能
Nginx通过模块化的设计,可以实现多种HTTP请求处理功能。
- 静态内存服务
- 直接从文件系统中读取文件并将其作为HTTP响应发送给客户端
- 反向代理
- Nginx可以作为反向代理服务器,将客户端请求转发给后端服务器(数据库服务器等),并将后端服务器的响应返回给客户端
- 负载均衡
- 就爱那个客户端请求分发到多个后端服务器,从而实现负载均衡,提升系统的可拓展性和可靠性
- SSL/TLS加密
- 为HTTP请求提供安全的传输通道,保护数据的安全
- 缓存
- 可以缓存后端服务器的响应,减少后端服务器的负载,提高其响应速度
- 访问控制
- 通过IP地址、用户代理等方式进行访问控制,限制特定客户端的访问权限
- URL重写和重定向
- 压缩
- 对HTTP响应进行gzip压缩,坚守传输数据量,提高传输效率
- 限流
- 提供限流功能,限制客户端的请求速率,防止恶意请求或者流量供给
- 动静分离
- 根据文件类型,将动态和动态请求进行分离管理