Nginx 源码阅读-HTTP请求处理

内容概述

  • 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压缩,坚守传输数据量,提高传输效率
  • 限流
    • 提供限流功能,限制客户端的请求速率,防止恶意请求或者流量供给
  • 动静分离
    • 根据文件类型,将动态和动态请求进行分离管理

 

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值