乐趣区

关于nginx:nginx学习笔记二

handler 模块

作为第三方开发者咱们最有可能开发的三种类型的模块别离是:handler、filter 和 load-balancer。配置文件应用 location 指令能够配置 content handler 模块,每个 handler 都有一次机会把本人关联到对应的 location 上。

模块根本构造

大家都晓得 Nginx 的配置信息分成了几个作用域 (scope, 有时也称作上下文),这就是 main, server, 以及
location。同样的每个模块提供的配置指令也能够呈现在这几个作用域里。那对于这三个作
用域的配置信息,每个模块就须要定义三个不同的数据结构去进行存储。

typedef struct {
    int count; //count
    struct in_addr addr; //ip
} ngx_pv_table;

模块配置指令

一个模块的配置指令是定义在一个动态数组中的。

struct ngx_command_s {
    ngx_str_t             name; // 名称
    ngx_uint_t            type; // 类型例如是 main 配置还是 location 配置以及有无参数
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // 回调函数,解析到该命令之后,执行该函数
    ngx_uint_t            conf;// 是不是 http module
    ngx_uint_t            offset;// 指定该配置项值的准确寄存地位,个别指定为某一个构造体变量的字段便宜。void                 *post;
};

模块上下文构造

这是一个 ngx_http_module_t 类型的动态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创立存储配置信息的对象的函数,也有在创立前和创立后会调用的函数。这些函数都将被 nginx 在适合的工夫进行调用。

typedef struct {ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);// 在创立和读取该模块的配置信息之前被调用
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);// 在创立和读取该模块的配置信息之后被调用

    void       *(*create_main_conf)(ngx_conf_t *cf);// 调用该函数创立本模块位于 http block 的配置信息存储构造。该函数胜利的时候,返回创立的配置对象。失败的 u 话,返回 NULL
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);// 调用该函数初始化本模块位于 http block 的配置信息存储构造。该函数胜利的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或谬误字符串。void       *(*create_srv_conf)(ngx_conf_t *cf);// 调用该函数创立本模块位于 http server block 的配置信息存储构造,每个 server block 会创立一个。该函数胜利的时候,返回创立的配置对象。失败的话,返回 NULL。char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);// 因为有些配置指令既能够呈现在 http block,也能够呈现在 http server block 中。那么遇到这种状况,每个 server 都会有本人存储构造来存储该 server 的配置,然而在这种状况下 http block 中的配置与 server block 中的配置信息发生冲突的时候,就须要调用此函数进行合并,该函数并非必须提供,当预计到相对不会产生须要合并的状况的时候,就无需提供。当然为了平安起见还是倡议提供。该函数执行胜利的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或谬误字符串

    void       *(*create_loc_conf)(ngx_conf_t *cf);// 调用该函数创立本模块位于 location block 的配置信息存储构造。每个在配置中指明的 location 创立一个。该函数执行胜利,返回创立的配置对象。失败的话,返回 NULL。char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;

模块定义

对于开发一个模块来说,咱们都须要定义一个 ngx_module_t 类型的变量来阐明这个模块自身的信息,从某种意义上来说,这是这个模块最重要的一个信息,它通知了 nginx 这个模块的一些信息,下面定义的配置信息,还有模块上下文信息,都是通过这个构造来通知 nginx 零碎的,也就是加载模块的下层代码,都须要通过定义的这个构造,来获取这些信息。咱们先来看下 ngx_module_t 的定义

struct ngx_module_s {
    ngx_uint_t            ctx_index;
    ngx_uint_t            index;

    char                 *name;

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;

    ngx_uint_t            version;
    const char           *signature;

    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;

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

个别咱们能够这么定义

ngx_module_t  ngx_epoll_module = {
    NGX_MODULE_V1,
    &ngx_epoll_module_ctx,               /* module context */
    ngx_epoll_commands,                  /* module directives */
    NGX_EVENT_MODULE,                    /* module type */
    NULL,                                /* init master */
    NULL,                                /* init module */
    NULL,                                /* init process */
    NULL,                                /* init thread */
    NULL,                                /* exit thread */
    NULL,                                /* exit process */
    NULL,                                /* exit master */
    NGX_MODULE_V1_PADDING
};

handler 编写步骤

typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r); 提供处理函数。

  1. 编写模块根本构造。包含模块的定义,模块上下文构造,模块的配置构造等。
  2. 实现 handler 的挂载函数。依据模块的需要抉择正确的挂载形式。
  3. 编写 handler 处理函数。模块的性能次要通过这个函数来实现。

http 模块解决流程

nginx 的 http 解决流程蕴含 11 个阶段,这 11 个阶段是精华

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,

    NGX_HTTP_SERVER_REWRITE_PHASE,

    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,

    NGX_HTTP_PREACCESS_PHASE,

    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,

    NGX_HTTP_PRECONTENT_PHASE,

    NGX_HTTP_CONTENT_PHASE,

    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

这些阶段当中咱们最次要关注的是 content 阶段,每个阶段都有若干个 handler 函数。通过 ngx_http_init_phase_handlers 函数将这个 handler 函数填入引擎组。

        for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) {
            ph->checker = checker;
            ph->handler = h[j];
            ph->next = n;
            ph++;
        }// 将 handler 填入引擎组的外围代码,后面通过 switch case 来判断每个阶段

具体 handler 的执行在函数 ngx_http_core_phases(ngx_http_request_t *r).

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) {rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
        //r->phase_handler 的变换在 checker 中执行,checker 执行该阶段中的 checker 函数,checker 函数中执行 handler 函数,checker 自身用来判断是否满足执行 handler 函数的条件
        if (rc == NGX_OK) {return;}
    }
}
退出移动版