`
simohayha
  • 浏览: 1400220 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

nginx中handler的处理(一)

阅读更多
nginx中的处理一个http的请求分为了8个phase,分别是下面几个阶段.

其中特别要注意就是几个rewrite阶段。
typedef enum {
//读取请求phase
    NGX_HTTP_POST_READ_PHASE = 0,
//接下来就是开始处理

//这个阶段主要是处理全局的(server block)的rewrite。
    NGX_HTTP_SERVER_REWRITE_PHASE,
//这个阶段主要是通过uri来查找对应的location。然后将uri和location的数据关联起来
    NGX_HTTP_FIND_CONFIG_PHASE,
//这个主要处理location的rewrite。
    NGX_HTTP_REWRITE_PHASE,
//post rewrite,这个主要是进行一些校验以及收尾工作,以便于交给后面的模块。
    NGX_HTTP_POST_REWRITE_PHASE,
//比如流控这种类型的access就放在这个phase,也就是说它主要是进行一些比较粗粒度的access。
    NGX_HTTP_PREACCESS_PHASE,

//这个比如存取控制,权限验证就放在这个phase,一般来说处理动作是交给下面的模块做的.这个主要是做一些细粒度的access。
    NGX_HTTP_ACCESS_PHASE,
//一般来说当上面的access模块得到access_code之后就会由这个模块根据access_code来进行操作
    NGX_HTTP_POST_ACCESS_PHASE,

//try_file模块,也就是对应配置文件中的try_files指令。
    NGX_HTTP_TRY_FILES_PHASE,
//内容处理模块,我们一般的handle都是处于这个模块
    NGX_HTTP_CONTENT_PHASE,
//log模块
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;



这里要注意的就是这几个phase的执行是严格按照顺序的,也就是NGX_HTTP_POST_READ_PHASE是第一个,而LOG_PHASE是最后一个。只有一个特殊那就是FIND_CONFIG_PHASE,这个的话,有可能会在后面的rewrite phase再来调用这个phase。

这里handler的结构是这样的,在ngx_http_core_main_conf_t中会有一个包含了ngx_http_phase_t结构的数组,而ngx_http_phase_t包含了一个动态数组,也就是说每一个phase都有一个handler数组。

typedef struct {
...................................................................
    ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

typedef struct {
//每个phase都会有一个handler数组。
    ngx_array_t                handlers;
} ngx_http_phase_t;



然后每个handler数组的元素都是一个hanler函数。

typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);


也就是我们写handler的时候注册的handler函数。

ok,接下来我们来看phase的初始化,初始化函数是ngx_http_init_phase_handlers。

在看phase初始化之前,我们先来看一个叫做ngx_http_phase_handler_s的结构体,这个结构体是保存在ngx_http_core_main_conf_t 中的,最终我们通过上面所讲的phases注册的handler链会被转换为ngx_http_phase_handler_s,然后保存在ngx_http_core_main_conf_t的phase_engine中。而后面对handler的调用处理都是使用ngx_http_phase_handler_s。

这个结构体是每个handler都会有一个的,也就是说所有的phase handler最终都会链接到一个大的数组中,这个大数组就是ngx_http_phase_engine_t的handlers域。

typedef struct {
//所有的hanler都会在这个数组中.
    ngx_http_phase_handler_t  *handlers;
    ngx_uint_t                 server_rewrite_index;
    ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;


然后我们来看它的每个域的含义。

checker  所有处于相同phase的handler的check都是相同的,每个phase的handler的调用都是在check中的,也就是check进行一些校验,结果判断等等操作。

handler就是对应的handler处理函数

ngxt 表示了下一个要执行的handler(也就是ngx_http_phase_handler_s)的位置,由于是数组,所以这个也就表示数组索引。而这个默认就是下一个将要执行的phase

struct ngx_http_phase_handler_s {
    ngx_http_phase_handler_pt  checker;
    ngx_http_handler_pt        handler;
    ngx_uint_t                 next;
};



来看函数的实现,其实功能很简单,就是初始化ngx_http_phase_handler_s,将我们注册的handler都链接到这个数组中,然后还有一些校验等。

这里要注意有些phase的话只会有一个handler,比如CONFIG_PHASE,下面的代码中我们会详细看到。


static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
    ngx_int_t                   j;
    ngx_uint_t                  i, n;
    ngx_uint_t                  find_config_index, use_rewrite, use_access;
    ngx_http_handler_pt        *h;
//最终的handler数组
    ngx_http_phase_handler_t   *ph;
    ngx_http_phase_handler_pt   checker;

    cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
    cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
    find_config_index = 0;
//是否有使用rewrite以及access。
    use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
    use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;

//开始计算handler 数组的大小
    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;
    }

//数组分配内存
    ph = ngx_pcalloc(cf->pool,
                     n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
    if (ph == NULL) {
        return NGX_ERROR;
    }

//handler数组放到handlers里面。
    cmcf->phase_engine.handlers = ph;
//n表示下一个phase的索引。
    n = 0;

//开始遍历phase handler.这里是一个phase一个phase的遍历。
    for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
//取出对应的handler处理函数
        h = cmcf->phases[i].handlers.elts;
//根据不同的phase来处理
        switch (i) {
//server重写phase(也就是内部重定向phase)
        case NGX_HTTP_SERVER_REWRITE_PHASE:
//如果有定义重写规则则设置重写handler的索引n.
            if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
                cmcf->phase_engine.server_rewrite_index = n;
            }
//赋值checker
            checker = ngx_http_core_generic_phase;

            break;
//config phase只有一个.这里设置 find_config_index,是因为当我们rewrite之后的url就必须重新挂载location的一些结构,因此就需要再次进入这个phase
        case NGX_HTTP_FIND_CONFIG_PHASE:
            find_config_index = n;
//自己的checker
            ph->checker = ngx_http_core_find_config_phase;
            n++;
            ph++;

            continue;

//rewrite phase
        case NGX_HTTP_REWRITE_PHASE:
            if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
                cmcf->phase_engine.location_rewrite_index = n;
            }
//共用的checker
            checker = ngx_http_core_generic_phase;

            break;

        case NGX_HTTP_POST_REWRITE_PHASE:
//如果有使用rewrite则给它的checker赋值
            if (use_rewrite) {
                ph->checker = ngx_http_core_post_rewrite_phase;
//注意它的next就是find_config phase,也就是说需要重新挂载location的数据。
                ph->next = find_config_index;
                n++;
                ph++;
            }

            continue;

        case NGX_HTTP_ACCESS_PHASE:
            checker = ngx_http_core_access_phase;
            n++;
            break;

        case NGX_HTTP_POST_ACCESS_PHASE:
            if (use_access) {
                ph->checker = ngx_http_core_post_access_phase;
                ph->next = n;
                ph++;
            }
            continue;

        case NGX_HTTP_TRY_FILES_PHASE:
            if (cmcf->try_files) {
                ph->checker = ngx_http_core_try_files_phase;
                n++;
                ph++;
            }

            continue;

        case NGX_HTTP_CONTENT_PHASE:
            checker = ngx_http_core_content_phase;
            break;

        default:
            checker = ngx_http_core_generic_phase;
        }

//这里n刚好就是下一个phase的其实索引
        n += cmcf->phases[i].handlers.nelts;

//开始遍历当前的phase的handler。
        for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
            ph->checker = checker;
//每个的handler就是注册的时候的回掉函数
            ph->handler = h[j];
//next为下一个phase的索引
            ph->next = n;
//下一个handler
            ph++;
        }
    }

    return NGX_OK;
}


这里需要注意就是只有下面这几个phase会有多个handler,剩余的都是只有一个handler的。

NGX_HTTP_POST_READ_PHASE 
    NGX_HTTP_SERVER_REWRITE_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_PREACCESS_PHASE,
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_CONTENT_PHASE,
    NGX_HTTP_LOG_PHASE


接下来我们来看phase的启动。

phase的启动是在ngx_http_core_run_phases这个函数中的,这个函数会遍历所有phase然后调用他们的checker来进行处理,也就是说错误,返回代码的控制什么的都是由各自的checker做的。而所有的checker的返回值都是一样的。

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

//调用checker
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
//如果有一个checker返回OK,则后面的phase就不会处理的。
        if (rc == NGX_OK) {
            return;
        }
    }
}


分享到:
评论

相关推荐

    补充:Nginx之模块处理流程

    如果多个处理模块映射到了同一个位置,Nginx会在配置文件中处理冲突,确保只有一个模块处理请求。 3. **过滤模块(Filter Modules)**:过滤模块在处理模块之后介入,用于修改或增强处理模块生成的输出。例如,它们...

    nginx源码vs工程-自定义handler处理-创建子请求处理逻辑-filter过滤器中处理应答

    *本工程功能: 1.windows下vs2019工程编译nginx源码,可正常编译运行。... (此处从请求头中检测是否有对应字段,有则进入处理,否则往下一阶段处理) 7.添加cJson库解析处理接收到的数据 8.自定义的handle

    第一个Nginx模块的例子

    标题中的“第一个Nginx模块的例子”意味着我们将探讨如何创建一个自定义的Nginx模块。Nginx是一个高性能的Web服务器和反向代理服务器,它以其轻量级、高并发处理能力而闻名。开发自定义模块可以让用户扩展Nginx的...

    Nginx开发从入门到精通

    - **handler模块简介**:Handler模块是Nginx中用于处理特定类型的请求的核心组件。 - **模块的基本结构**:每个Handler模块都需要实现一组特定的接口函数,以完成其功能。 - **handler模块的基本结构**:Handler模块...

    nginx上传下载之nginx-upload-module-2.3.0

    **Nginx Upload Module 2.3.0 ...总之,Nginx Upload Module 2.3.0 提供了一种有效的方式来管理和处理大文件上传,为开发者提供了更多的灵活性和控制力。正确配置和使用这个模块,能够极大地提升 Web 应用的用户体验。

    Nginx+upload+lua实现简单文件上传服务

    创建一个处理文件上传的lua脚本,例如`upload_handler.lua`,这个脚本会接收Nginx传递的文件信息,并进行处理,如保存文件、验证文件大小和类型等。示例脚本可能如下: ```lua local function save_file(file) ...

    nginx module开发指南(中文版)

    - **Handler 的调用**: 在启动过程中,每个 handler 有机会处理配置文件中的 location 定义。如果有多个 handler 被配置来处理同一 location,则只有一个 handler 可以“获胜”,即被选中来处理该 location。 - **...

    nginx开发从入门到精通

    从给定文件中可以看出,这是一本关于nginx开发的书籍,内容涵盖了nginx模块开发、原理解析以及架构详解等多个方面。下面将详细介绍这些知识点。 首先,nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3...

    nginx脚本引擎与rewrite设计原理(一)

    在配置解析过程中,Nginx会为每个配置项创建一个包含关键信息的结构体,并关联相应的处理函数(handler)。这些处理函数会在特定的请求处理阶段(如REWRITE_PHASE)被集中调用,以实现rewrite规则的动态解析和应用。...

    Nginx从入门到精通

    - **多阶段处理请求**:Nginx通过多个阶段来处理一个请求,每个阶段可以由不同的模块处理。 - **返回响应数据**:客户端发送请求后,Nginx会生成相应的响应内容。 - **pipeline请求**:一种特殊的请求处理方式,...

    nginx-rtmp模块源码包nginx-rtmp-module-master

    Nginx-RTMP 模块是 Nginx 的一个扩展,用于处理 Real-Time Messaging Protocol (RTMP) 流,它允许 Nginx 作为 RTMP 服务器运行,支持直播和点播服务。这个源码包 "nginx-rtmp-module-master" 包含了 Nginx-RTMP 模块...

    nginx1.16.1+nginx-upload-module-2.3.0.zip

    总的来说,"nginx1.16.1+nginx-upload-module-2.3.0.zip" 提供了一种实现大文件上传的解决方案,结合了 Nginx 的稳定性和 nginx-upload-module 的便捷性,使得在 Web 应用中处理文件上传变得更加高效和可控。...

    nginx-rtmp模块

    Nginx-RTMP模块是一款强大的开源软件扩展,它将Nginx服务器的功能扩展到了实时传输协议(Real-Time Messaging Protocol, RTMP)领域,使得Nginx能够处理流媒体内容,如直播和点播服务。这个模块是由Alexey Kuznetsov...

    nginx源代码1.13.10

    Nginx是一款高性能的Web服务器和反向代理服务器,以其轻量级、高并发、稳定性强的特点在互联网行业中广泛应用。Nginx 1.13.10是2018年的最新版本,它的发布带来了许多性能优化和功能增强,对于Linux服务器的部署和...

    Nginx开发从入门到精通.pdf

    handler模块在Nginx架构中起着核心的作用,因为每一个HTTP请求最终都会由一个handler模块来处理。 《Nginx开发从入门到精通》这本书是由淘宝核心系统服务器平台组成员创作的,他们利用在淘宝内部使用Nginx的经验和...

    windows版本nginx1.7 + rtmp模块

    Nginx 是由 Igor Sysoev 开发的一款开源 Web 服务器,以其高并发处理能力、低内存占用以及稳定性能而著名。它采用了事件驱动的异步非阻塞模型,能够同时处理大量连接请求。Nginx 支持 HTTP、HTTPS、SMTP、IMAP/POP3 ...

    nginx-lua-GraphicsMagick

    为了提高图片处理效率并减轻服务器负担,我们可以利用Nginx的Lua模块与GraphicsMagick工具来构建一个动态的图片切割和缩放服务。下面我们将详细讲解这个服务的搭建过程。 ### 1. 搭建GraphicsMagick服务 **...

    深入剖析Nginx

    然后,分别深入分析了Nginx的进程模型、数据结构、配置指令、主要功能模块、I/O事件处理、变量机制、客户端请求过程、Filter模块实例、负载均衡策略以及Handler模块等。附录部分提供了Nginx的编译模块、运行配置等...

Global site tag (gtag.js) - Google Analytics