源码:nginx 1.12.0     
     nginx由于其高性能、扩充性好等特点在迅速走红,越来越多的公司采用nginx作web服务器、负载均衡、waf等 工作,一些基于nginx二次开发的openresty、tengine等开源软件也迅速在相关领域走红。
 
     虽然nginx有对应的windows版本,但是不建议使用。因为windows环境下缺少epoll(linux)、devpoll(bsd)这样高效的事件通知方案,实际性能与linux/BSD环境下的差别很多。关于nginx的event模块这篇文章不展开讲,这里主要讲nginx能实现负载均衡、waf等不同功能的原因——http module。
     http模块整体处理流程如下:
     根据上图,phase handler以及filter各个类型的主要初始化工作就是在postconfiguration函数中,下面代码片段中也有介绍。
 
    一、phase handlers阶段
     nginx对http的请求处理分成了POST_READ, SERVER_REWRITE, FIND_CONFIG, REWRITE, POST_REWRITE, PREACCESS, ACCESS, POST_ACCESS, TRY_FILES, CONTENT, LOG这几个阶段,除了FIND_CONFIG, POST_WRITE, POST_ACCESS, TRY_FILES这四个阶段用户不能添加自定义的处理函数,其余每个阶段都初始化了一个数组用于保存本阶段的处理函数指针。如下:

//////   nginx/src/http/ngx_http.c ////////
static ngx_int_t
ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
    if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)  {
        return NGX_ERROR;
    }
    .....
    .....
    if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK) {
        return NGX_ERROR;
    }

    return NGX_OK;
}

///// nginx/src/http/modules/ngx_http_rewrite_module.c /////
static ngx_int_t
ngx_http_rewrite_init(ngx_conf_t *cf)
{
    ngx_http_handler_pt        *h;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
     //在&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers指向的数组中申请一个函数指针空间
    h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }
     //将函数添加到数组中新申请的元素中
    *h = ngx_http_rewrite_handler;

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }
    *h = ngx_http_rewrite_handler;

    return NGX_OK;
}

//////   nginx/src/http/ngx_http.c ////////
static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
    cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
    cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
    find_config_index = 0;
    use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
    use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;

    n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;

    for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
        n += cmcf->phases[i].handlers.nelts;
    }

     //为phase
    ph = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
    if (ph == NULL) {
        return NGX_ERROR;
    }

    cmcf->phase_engine.handlers = ph;
    n = 0;

    for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
        h = cmcf->phases[i].handlers.elts;
        switch (i) {
        case NGX_HTTP_SERVER_REWRITE_PHASE:
            if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
                cmcf->phase_engine.server_rewrite_index = n;
            }
          //根据phase阶段确定每个阶段对应的checker
            checker = ngx_http_core_rewrite_phase;
            break;
        .....
        .....
        case NGX_HTTP_CONTENT_PHASE:
            checker = ngx_http_core_content_phase;
            break;

        default:
            checker = ngx_http_core_generic_phase;
        }

        n += cmcf->phases[i].handlers.nelts;
        //遍历各个phase handlers数组中的注册函数并统一添加到cmcf->phase_engine.handlers中
        for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
            ph->checker = checker;
            ph->handler = h[j];
            ph->next = n;
            ph++;
        }
    }
    return NGX_OK;
}

/////  nginx/src/http/ngx_http_core_module.c ////////
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
    ngx_int_t                   rc;
    ngx_http_phase_handler_t   *ph;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    ph = cmcf->phase_engine.handlers;

    while (ph[r->phase_handler].checker) {
          //根据请求中的phase索引确定执行的checker函数
          //checker函数根据处理结果来决定是结束处理还是继续下一个phase
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
        if (rc == NGX_OK) {
            return;
        }
    }
}
 
二、filter类型模块
     filter类型主要是在输出的时候对输出内容进行处理,filter类型的各个模块的调用顺序与phase handler类型(根据phase阶段顺序)不同,filter类型的各个模块是通过链表的形式联系到一块的,只有链表头ngx_http_top_body_filter 函数指针是全局的,遍历顺序跟在配置文件定义的顺序(nginx/auto/modules中ngx_module_order)相反。
     在各个module初始化的时候,会将ngx_http_top_body_filter指针的值保存到ngx_http_next_body_filter局部变量中,然后把当前filter的处理函数赋值给ngx_http_top_body_filter,同时每个filter的处理函数中都将ngx_http_next_body_filter的值赋值给ctx->output_filter,以便可以顺序遍历各个filter。
     对于ngx_http_write_filter_module、ngx_http_header_filter_module两个模块中没有ngx_http_next_body_filter变量,是因为ngx_http_write_filter_module是最后一个filter模块,因此不用next。ngx_http_header_filter_module虽然是倒数第二个模块,但是filter函数中调用了write_filter的函数,因此也没有使用next。

///// nginx/src/http/ngx_http_core_module.c ///////
ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
   .....
    //通过链表接口来一次遍历各个filter模块进行处理
    rc = ngx_http_top_body_filter(r, in);
    .....
    return rc;
}

///// nginx/src/http/ngx_http_copy_filter_module.c //////////
static ngx_int_t
ngx_http_copy_filter_init(ngx_conf_t *cf)
{
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_copy_filter;

    return NGX_OK;
}

static ngx_int_t
ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    .....
    .....
    ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
    if (ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }
        ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);
        //记录下一个要执行的filter
        ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_body_filter;
        ctx->filter_ctx = r;
        ....
        ....
        if (in && in->buf && ngx_buf_size(in->buf)) {
            r->request_output = 1;
        }
    }
     .....
    rc = ngx_output_chain(ctx, in);
    .....
    return rc;
}

nginx学习笔记——http module分析的更多相关文章

  1. Nginx学习笔记4 源码分析

    Nginx学习笔记(四) 源码分析 源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_ ...

  2. python学习笔记之module && package

    个人总结: import module,module就是文件名,导入那个python文件 import package,package就是一个文件夹,导入的文件夹下有一个__init__.py的文件, ...

  3. UML和模式应用学习笔记-1(面向对象分析和设计)

    UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...

  4. Nginx学习笔记~目录索引

    回到占占推荐博客索引 前几天整理了<Docker的学习笔记索引>,受到了很多朋友的关注,今天把Nginx的文章也整理一下,以后将永久更新,像大叔之前的<EF文章系列>,< ...

  5. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

  6. ArcGIS案例学习笔记4_2_水文分析批处理地理建模

    ArcGIS案例学习笔记4_2_水文分析批处理地理建模 联系方式:谢老师,135_4855_4328,xiexiaokui#139.com 概述 计划时间:第4天下午 目的:自动化,批量化,批处理,提 ...

  7. ArcGIS案例学习笔记4_1_水文分析

    ArcGIS案例学习笔记4_1_水文分析 联系方式:谢老师,135_4855_4328,xiexiaokui#139.com 概述 计划时间:第4天上午 教程: pdf page478 数据:实验数据 ...

  8. nginx 学习笔记(2) nginx新手入门

    这篇手册简单介绍了nginx,并提供了一些可以操作的简单的工作.前提是nginx已经被安装到你的服务器上.如果没有安装,请阅读上篇:nginx 学习笔记(1) nginx安装.这篇手册主要内容:1. ...

  9. Nginx学习笔记之加强篇

    在上一篇文章Nginx学习笔记之应用篇中,我们已经可以正式运行自己的网站了.但是在使用Nginx服务器时还需要注意几个问题: 1.Nginx服务器上配置的单个站点的并发量不超过1024 2.Nginx ...

随机推荐

  1. progID

    ProgID程序员给CLSID指定的容易记住的名字ProgID命名约定:<Program>.<Component>.<Version>AppID:将某个APPID( ...

  2. 安全体系(二)——RSA算法详解

    本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...

  3. 2017-03-10 T-sql 语句 高级查询

    T-SQL语句: 创建数据库: 1,点击新建查询,在弹出的页面上进行代码编写.点击可用数据库,编写前确定当前操作的页面是自己想要进行操作的界面. 2,数据库创建语句 Create datebase   ...

  4. ACM 树形数组

    树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元 ...

  5. Greenplum 简单性能测试与分析

    如今,多样的交易模式以及大众消费观念的改变使得数据库应用领域不断扩大,现代的大型分布式应用系统的数据膨胀也对数据库的海量数据处理能力和并行处理能力提出了更高的要求,如何在数据呈现海量扩张的同时提高处理 ...

  6. Ionic2 开发笔记(1)ionic2 +angular2搭建

    1.去node.js官网下载对应版本https://nodejs.org/en/(不会请看OnsenUi搭载,里面有详细过程) 2.然后通过npm下载Ionic和cordova $ npm insta ...

  7. 3386/1752: [Usaco2004 Nov]Til the Cows Come Home 带奶牛回家

    3386/1752: [Usaco2004 Nov]Til the Cows Come Home 带奶牛回家 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit ...

  8. LODOP的一次使用后的总结

    一.lodop打印预览效果图 LODOP.PRINT_SETUP();打印维护效果图 LODOP.PREVIEW();打印预览图 二.写在前面 最近项目用到了LODOP的套打,主要用到两个地方,一是物 ...

  9. Robot Framework 使用笔记

    条件表达式: Run Keyword If 表达式 执行动作   ... ELSE IF 表达式 执行动作 ... ELSE 执行动作   基础格式见上表,下面是我遇到的坑: 表达式:判断字符串变量是 ...

  10. (25)IO流之转换流InputStreamReader和OutputStreamWriter

    InputStreamReader:字节到字符的桥梁. OutputStreamWriter:字符到字节的桥梁. 它们有转换作用,而本身又是字符流.所以在构造的时候,需要传入字节流对象进来. 构造函数 ...