Nginx Http框架的理解

HTTP框架是Nginx基础框架的一部分,Nginx的其它底层框架如master-worker进程模型、event模块、mail 模块等。

HTTP框架代码主要有2个模块组成:ngx_http_module和ngx_http_core_module;

我们编写的HTTP模块需要注册到HTTP框架上,才能融入HTTP请求的处理流程中。

当在nginx.conf中存在一个http{...}的配置时,即启用了HTTP框架代码,在nginx配置解析时,就已经为框架建立好了各种数据结构(尤其是HTTP模块的挂载);

当nginx收到请求时,请求完全按照HTTP框架建立好的这种逻辑进行处理。



一、HTTP模块开发基础

开发一个HTTP模块,需要下面几个数据结构:

1. HTTP模块配置结构
用于存储从配置文件读进来的相关指令参数;

配置模块的context有三种,分别是main、server和location,它们分别位于于http{...}、server{...}和location{...}上下文中。

其名称约定如下:ngx_http_<module name>_(main|srv|loc)_conf_t

2.HTTP 模块配置指令

模块的指令是定义在一个叫做ngx_command_t的静态数组中的;

ngx_command_t数组以ngx_null_command为终结符。

struct ngx_command_t {
    ngx_str_t             name;          // 指令名称
    ngx_uint_t            type;          // 指令所在的context和包含的参数个数
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);     // 解析配置,并将参数存入模块配置结构体中
    ngx_uint_t            conf;          // 指令参数的存储位置
    ngx_uint_t            offset;        // 指令参数的存储偏移量
    void                 *post;     
};

其中,

type 成员表明这个指令允许出现的context、参数个数:

* NGX_HTTP_MAIN_CONF:   指令出现在main配置部分是合法的

* NGX_HTTP_SRV_CONF:      指令在server配置部分出现是合法的 config

* NGX_HTTP_LOC_CONF:      指令在location配置部分出现是合法的

* NGX_HTTP_UPS_CONF:      指令在upstream配置部分出现是合法的

* NGX_CONF_NOARGS:        指令没有参数

* NGX_CONF_TAKE1:           指令读入1个参数

* NGX_CONF_TAKE7:           指令读入7个参数

* NGX_CONF_FLAG:             指令读入1个布尔型数据 ("on" or "off")

* NGX_CONF_1MORE:           指令至少读入1个参数

* NGX_CONF_2MORE:           指令至少读入2个参数

set 成员是一个函数指针,用于模块参数解析,可以将配置文件中的模块参数传递给模块;

该函数会在遇到指令时执行,函数有三个入参:

a. 指向结构体 ngx_conf_t 的指针, 这个结构体里包含需要传递给指令的参数
   b. 指向结构体 ngx_command_t 的指针
   c. 指向模块自定义配置结构体的指针

Nginx内部提供了多个函数用来保存特定类型的数据,这些函数包括:

* ngx_conf_set_flag_slot:      将 "on" or "off" 转换成 1 or 0

* ngx_conf_set_str_slot:           将字符串保存为 ngx_str_t

* ngx_conf_set_num_slot:       解析一个数字并保存为int

* ngx_conf_set_size_slot:        解析一个数据大小(如:"8k", "1m") 并保存为size_t

conf 成员告诉Nginx把数据存在模块的哪个context中

* NGX_HTTP_MAIN_CONF_OFFSET

* NGX_HTTP_SRV_CONF_OFFSET

* NGX_HTTP_LOC_CONF_OFFSET

offset 成员确定保存在结构体的哪个位置;

post 成员指向模块在读配置的时候需要的一些零碎变量,一般为NULL。

3. HTTP模块上下文结构
静态的ngx_http_module_t结构体,用来创建和合并三段context (main,server,location),

其命名方式一般是:ngx_http_<module name>_module_ctx,

typedef struct {
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);                                         //   在读入配置前调用
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);                                       //  在读入配置后调用,用于挂载handler
    void       *(*create_main_conf)(ngx_conf_t *cf);                                            // 在创建main配置时调用(比如,用来分配空间和设置默认值)
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);                            // 在初始化main配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)
    void       *(*create_srv_conf)(ngx_conf_t *cf);                                           // 在创建server配置时调用
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);          // 合并server和main配置时调用
    void       *(*create_loc_conf)(ngx_conf_t *cf);                                        // 创建location配置时调用,用于为指令参数结构体分配内存和初始化
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);         // 合并location和server配置时调用 
} ngx_http_module_t;

这些回调是在ngx_http_block()解析http{...}配置时完成的:

当遇到一个 http{...} 时,HTTP框架会调用所有HTTP模块可能实现的create_main_conf、create_srv_conf、create_loc_conf生成存储main级别配置参数结构体;

当遇到一个server{...}时,HTTP框架会调用所有HTTP模块可能实现的create_srv_conf、create_loc_conf生成存储server级别配置参数结构体;

当遇到一个location{...}时,HTTP框架会调用所有HTTP模块可能实现的create_loc_conf生成存储location级别配置参数结构体;

因此,我们开发的HTTP模块中create_loc_conf方法被调用的次数等于http{...}、server{...}、location{...}在nginx.conf出现的次数之和;

create_srv_conf方法被调用的次数等于server{...}、location{...}在nginx.conf出现的次数之和;

由于只有一个http{...},所以create_main_conf方法只会被调用一次;

HTTP创建了如此多的结构体来存放配置项,是为了解决同名配置项的合并问题。

4、HTTP模块定义

一个Nginx模块被定义为一个ngx_module_t 结构,

该结构体变量命名方式为ngx_http_<module-name>_module

它包含模块的内容和指令执行方式,同时还包含一些回调函数来处理线程/进程的创建和销毁;

模块定义在有的时候会被用作查找的关键字,来查找与特定模块相关联的数据。

struct ngx_module_s {
ngx_uint_t ctx_index;    // 在所有的HTTP模块中的序列号
ngx_uint_t index;      // 在所有模块中的序列号

ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;

ngx_uint_t version;

void *ctx;            // 模块上下文
ngx_command_t *commands;  // 模块配置指令
ngx_uint_t type;        // 模块类型,HTTP模块应为NGX_HTTP_MODULE

ngx_int_t (*init_master)(ngx_log_t *log);

ngx_int_t (*init_module)(ngx_cycle_t *cycle);

ngx_int_t (*init_process)(ngx_cycle_t *cycle);
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
void (*exit_thread)(ngx_cycle_t *cycle);
void (*exit_process)(ngx_cycle_t *cycle);

void (*exit_master)(ngx_cycle_t *cycle);

uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};

注意:在configure之后生成的文件 objs/ngx_modules.c 中包含了模块的编译顺序。



1、解析HTTP配置的流程

首先要理解 ngx_conf_parse() 的递归解析流程;

nginx在解析nginx.conf的时候,没读取一行配置项,就执行该配置项的解析回调(handler);

时间: 2024-08-29 13:35:15

Nginx Http框架的理解的相关文章

对于iOS前端框架的理解

iOS前端的架构设计,我所理解的意思就是,使用什么样的模式或者结构敲代码就是各个类怎么协同工作的.或者文件存放的结构.各个类到底如何分工的. 国外有好多关于iOS端的架构的文章,无奈实在英语水平有限,只看了几篇被翻译过的文章.MVC.MVVM.VIPER等还有几个记不住名字的,但是无论什么架构感觉理解的都不是很深刻,具体写代码的时候也没有分的太清楚,也是怎么方便怎么来.最后导致了来回几次的重构,但是重构完成后,过一段时间再看代码的时候还是感觉结构不够清晰,各个类之间的关系比较混乱.现在的项目也是

【nginx】【转】Nginx启动框架处理流程

Nginx启动过程流程图: ngx_cycle_t结构体: Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务以外,也必定是所有功能模块的入口之处.Nginx的初始化工作主要围绕一个类型为ngx_cycle_t类型的全局变量(cycle)展开. ngx_cycle_t结构体类型: typedef struct ngx_cycle_s ngx_cycle_t; struct ngx_cycle_s { voi

BI技术框架的理解

如何梳理BI技术框架? 首先,我们需要从各个菜市场(数据源)挑选我们需要的蔬菜.肉类.水果,然后我们开始挑拣.清洗,并根据菜式的要求,将各种原材料切好(ETL),摆放到厨房(数据仓库):然后厨师根据不同的菜式及口味,将原材料进行必要的搭配(OLAP),最后辅以调料,通过炒.焖.炖等不同烹饪的手法制作出不同的菜肴,最后端上桌的红烧鱼.铁板牛肉.凉拌青瓜.水果拼盘.玉米炖排骨则像是报表.仪表盘.柱状图.趋势线等各种各样的BI前端展示界面. 技术实现的过程也和做菜一样: 领导想吃什么菜,就得研究这道菜

详谈软件测试体系框架的理解

详谈软件测试体系框架的理解 测试应该站在两点至高点上思考问题:产品质量,和效率上 用这几点来思考问题:是什么,为什么,怎么办 用测试框架来筛选过滤测试点:测试框架有:功能测试,性能测试,可靠性测试,负载测试,易用性测试,强度测试,安全测试,配置测试,安装测试,卸载测试,文档测试,故障恢复测试,界面测试,容量测试,兼容性测试,分布测试. 用用例设计方法把测试点变成可执行的用例:如:等价类,边界值,输入域,场景分析法,错误推测法,等. 排序:再依次按照紧急程度,影响严重程度,安排计划这些事. 文档输

nginx学习笔记七(nginx HTTP框架的执行流程)

之前已经介绍过nginx的事件框架.那么,对于client发出的一个http的请求,nginx的http框架是如何一步步解析这个http请求?http框架又是如何和之前介绍过得epoll事件模块结合起来的,下面来简要介绍下. 注:我手头上的nginx工程是nginx-1.9.14的,与<深入理解nginx>的版本不一致,在http框架这块的代码上也有着较大的区别. 一.ngx_http_init_connection 在http框架初始化的时候(参见<深入理解nginx>第10章)

对SSH三大框架的理解

SSH框架一般指的是Struts.Spring.Hibernate,后来Struts2代替了Struts.最近5年,Struts2已经被Spring MVC代替,而Hibernate基本也被iBatis/MyBatis代替. 所以真正需要了解的是Spring,Spring需要了解两个概念AOP和IOC,更进一步就是Spring的核心技术"动态代理". 持久层框架看看Hibernate/iBatis/MyBatis,研究一下Spring的数据库事务管理,各个持久层框架式如何实现ORM的,

ios测试框架的理解

关于ios的测试 Cedar .Specta .Kiwi  .  XCTest Specta和Kiwi的区别就是Kiwi包含了Specta和OCmock以及Expeata所有的功能 测试框架的作用: 由于行业中的干进度,所以我们一般都是不用TDD来测试,而是用BDD来测试. BDD是用来测试的"数据存取"的重要环节. "术语" 理解: BDD(Behavior Driven Development),也就是行为驱动开发,它旨在解决具体问题,帮助开发人员确定应该测试些

ios測试框架的理解

关于ios的測试 Cedar .Specta .Kiwi  .  XCTest Specta和Kiwi的差别就是Kiwi包括了Specta和OCmock以及Expeata全部的功能 測试框架的作用: 因为行业中的干进度,所以我们一般都是不用TDD来測试,而是用BDD来測试. BDD是用来測试的"数据存取"的重要环节. "术语" 理解: BDD(Behavior Driven Development),也就是行为驱动开发.它旨在解决详细问题,帮助开发者确定应该測试些什

对于redis底层框架的理解(五)

之前总结了redis的通讯流程,基本框架,epoll的封装等等,这次介绍下 redis对于select模型的封装 //select 模型 typedef struct aeApiState { //读文件描述符集合,写文件描述符集合 fd_set rfds, wfds; /* We need to have a copy of the fd sets as it's not safe to reuse * FD sets after select(). */ //读写集合的副本 fd_set _