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);

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

  1. Nginx:HTTP框架是如何介入请求

    参考资料 <深入理解Nginx>(陶辉) Nginx事件模块博客地址:http://www.cnblogs.com/runnyu/p/4914698.html Nginx是一个事件驱动构架 ...

  2. iOS10通知框架UserNotification理解与应用

    iOS10通知框架UserNotification理解与应用 一.引言 关于通知,无论与远程Push还是本地通知,以往的iOS系统暴漏给开发者的接口都是十分有限的,开发者只能对标题和内容进行简单的定义 ...

  3. Java面试之五大框架的理解

    五大框架(springMVC,struts2,spring,mybatis,hibernate) 说说你对springMVC框架的理解? 简要口述(如果感觉说的少可以在完整答案里面挑几条说) Spri ...

  4. 对SSH三大框架的理解

    SSH框架一般指的是Struts.Spring.Hibernate,后来Struts2代替了Struts.最近5年,Struts2已经被Spring MVC代替,而Hibernate基本也被iBati ...

  5. Nginx学习之十一-Nginx启动框架处理流程

    Nginx启动过程流程图 下面首先给出Nginx启动过程的流程图: ngx_cycle_t结构体 Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个N ...

  6. nginx配置之深入理解

    继上一篇<debian+nginx配置初探--php环境.反向代理和负载均衡>成功之后,有点小兴奋,终于不用整lvs那么复杂来搞定负载,但还是有很多概念没弄清楚. 什么是CGI.FastC ...

  7. Django_web框架的理解

    web框架的本质 import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen() while T ...

  8. 对spring框架的理解

    spring框架的两大核心理念就是IOC和AOP,在面试的时候经常会被问到你对spring的理解.下面大致的说一下我对spring的理解. 一.IoC 1.1.什么是IoC 众所周知,IoC就是控制反 ...

  9. nginx 限速最容易理解的说明

    nginx 限速研究汇报 写在前面 这两天服务器带宽爆了,情况如下图: 出于降低带宽峰值的原因,我开始各种疯狂的研究nginx限速.下面是我研究过程中的心得!(花了好几个小时的时间写的人生第一篇技术类 ...

随机推荐

  1. C# 【无法修改XX返回值,因为它不是变量】

    using UnityEngine; using System.Collections; using System.Xml.Linq; using UnityEditor; using System; ...

  2. 20135202闫佳歆--week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程--实验及总结

    week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.gi ...

  3. Linux第14周学习笔记

    虚拟存储器 虚拟存储器是硬件异常.硬件地址翻译.主存.磁盘文件和内核软件的完美交互. 虚拟存储器的特点: 中心的 强大的 危险的 物理和虚拟寻址 计算机系统的主存被组织成一个由M个连续的字节大小的单元 ...

  4. i春秋——春秋争霸write up

    i春秋--春秋争霸write up 第一关 题目给出一张图 提示中,这种排列源于古老的奇书,暗含了两个数字,可以得出第一关的答案是两个数字 百度识图来一发, 得到图中排列是来自于洛书,点开洛书的百度百 ...

  5. MVC5 + EF6 + Bootstrap3 (9) HtmlHelper用法大全(下)

    文章来源:Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc5-ef6-bs3-get-started-httphelper-part2.html 上一节 ...

  6. iOS端给unity发送消息,实现两者交互。

    上一篇我们简单说了一下unity发消息给iOS端.现在我们就来说一下iOS端给unity发送消息的简单使用. 首先iOS端做得事情其实很简单就一句话,直接上代码 /** * 第一个参数:是unity那 ...

  7. 手把手教你Linux服务器集群部署.net网站 - 让MVC网站运行起来

    一.Linux下面安装需要软件 我们这里需要安装的软件有: 1) Mono 3.2.8 : C#跨平台编译器,能使.Net运行与Linux下,目前.net 4.0可以完美运行在该平台下 2) ngin ...

  8. 初识 swift 封装轮播图

    一.简介 换了一家公司.换了一个环境刚开始来公司自然不能有一丝一毫的放松,每天即使是没有什么工作也是看看这个博客.那个源码.尽量让自己更充实.慢慢的开始写几篇博客记录下自己遇到的一些问题和解决方法.其 ...

  9. 疯狂的Java算法——插入排序,归并排序以及并行归并排序

    从古至今的难题 在IT届有一道百算不厌其烦的题,俗称排序.不管是你参加BAT等高端笔试,亦或是藏匿于街头小巷的草根笔试,都会经常见到这样一道百年难得一解的问题. 今天LZ有幸与各位分享一下算法届的草根 ...

  10. 一个HTML5老兵坦言:我们真的需要“小程序”么?

    在PC时代,浏览器成为互联网信息的入口,并非因为它支持了HTML技术,而是因为它给人类带来了“世界是平的”的空间和理念,人类历史上第一次实现了信息的互联互通. 今天,微信虽然用了HTML5技术来做应用 ...