NGINX(六)扩展

前言

nginx模块化设计, 添加扩展模块变得容易, 下面开发一个非常简单的扩展模块, 实现返回http请求的头部内容, 配置标记是ping_pong, 配置在NGX_HTTP_LOC_CONF中.

HTTP处理阶段

nginx处理http请求分为很多的阶段, 下面列出了所有阶段, 服务器接收到完http请求头部内容后, 会依次执行各个阶段, 执行顺序按照全局ngx_modules数组中的顺序进行. ngxin如何知道我们的模块是http处理的一个阶段呢, 阶段模块在初始化时, 要将自己注册进模块列表中, 后面我们自己模块代码会有体现.

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_TRY_FILES_PHASE,
	
	/*http请求内容处理, 生成内容, 过滤操作, 我们要实现的简单扩展就注册在这个阶段*/
    NGX_HTTP_CONTENT_PHASE,

    NGX_HTTP_LOG_PHASE
} ngx_http_phases;


/*
 *http请求头部接收完之后, 会执行ngx_http_core_run_phases函数, 函数遍历所有阶段进行执行.
 */
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]);
		
		/*一旦有阶段返回NGX_OK标记, 则立即返回, 后面的阶段不再执行*/
        if (rc == NGX_OK) {
            return;
        }
    }
}

ps : 各个阶段具体处理什么参考博客 http://blog.csdn.net/fengmo_q/article/details/8594610

编译选项

--with-http_ping_pong_module

编译配置:

1.1.auto/options中添加

--with-http_ping_pong_module)    HTTP_PING_PONG=YES         ;;

2.2.auto/modules中添加

if [ $HTTP_PING_PONG = YES ]; then
    HTTP_MODULES="$HTTP_MODULES $HTTP_PING_PONG_MODULE"
    HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_ping_pong_module.c"
fi

3.3.auto/sources中添加

HTTP_PING_PONG_MODULE=ngx_http_ping_pong_module
HTTP_PING_PONG_SRCS=src/http/modules/ngx_http_ping_pong_module.c

nginx.conf中配置示例

    server {
        listen       88;

        location /test {
            ping_pong on;
        }
    }

完整ngx_http_ping_pong_module.c

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>


static ngx_int_t ngx_http_ping_pong_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_ping_pong_init(ngx_conf_t *cf);
static char* ngx_http_ping_pong_set_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void* ngx_http_ping_pong_create_loc_conf(ngx_conf_t *cf);

typedef struct{
    ngx_int_t ping_pong;
}ngx_http_ping_pong_loc_conf_t;

static ngx_command_t ngx_http_ping_pong_commands[] = {
    
    { ngx_string("ping_pong"),
      NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
      ngx_http_ping_pong_set_conf,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_ping_pong_loc_conf_t, ping_pong),
      NULL },

    ngx_null_command
};

ngx_http_module_t  ngx_http_ping_pong_module_ctx = {
    NULL,                                  /* preconfiguration */
    ngx_http_ping_pong_init,               /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_ping_pong_create_loc_conf,    /* create location configuration */
    NULL                                   /* merge location configuration */
};


ngx_module_t  ngx_http_ping_pong_module = {
    NGX_MODULE_V1,
    &ngx_http_ping_pong_module_ctx,        /* module context */
    ngx_http_ping_pong_commands,           /* module directives */
    NGX_HTTP_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
};

/*
 *  阶段处理的回调函数
 */
static ngx_int_t
ngx_http_ping_pong_handler(ngx_http_request_t *r)
{
    ngx_int_t rc;
    ngx_buf_t* b;
    ngx_chain_t out;
    ngx_uint_t content_length = 0;
    u_char ngx_ping_pong_string[1024] = {0};
    ngx_http_ping_pong_loc_conf_t* lcf;
	
	/*获取并检查是否配置了ping_pong标记*/
    lcf = ngx_http_get_module_loc_conf(r, ngx_http_ping_pong_module);
    if (lcf->ping_pong == NGX_CONF_UNSET)
    {
		/*如果没有进行配置, 则继续执行后面阶段*/
        return NGX_DECLINED;
    }
	
	/* 格式化输出的内容 */
    ngx_sprintf(ngx_ping_pong_string, "%V:%V,%V,%V  %V:%V", &r->method_name, &r->uri, &r->args, &r->request_line,  &r->headers_in.host->key, &r->headers_in.host->value);
    content_length = ngx_strlen(ngx_ping_pong_string);
	
	/*丢弃请求内容, 用不到*/
    rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK)
        return rc;

    ngx_str_set(&r->headers_out.content_type, "text/html");

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;

    out.buf = b;
    out.next = NULL;
	
	/*构造一个输出buf*/
    b->pos = ngx_ping_pong_string;
    b->last = ngx_ping_pong_string + content_length;
    b->memory = 1;
    b->last_buf = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = content_length;
	
	/*http响应头部返回给客户端*/
    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
        return rc;
	
	/*http响应内容返回给客户端*/
    return ngx_http_output_filter(r, &out);
}

/*
 *由于我们配置非常简单, 因此这里其实不用单独写set函数的, 可以直接将ngx_conf_set_flag_slot配置到command配置中
 */
static char*
ngx_http_ping_pong_set_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char* rv = ngx_conf_set_flag_slot(cf, cmd, conf);
    return rv;
}

/*
 *初始化配置
 */
static void*
ngx_http_ping_pong_create_loc_conf(ngx_conf_t *cf)
{
    ngx_http_ping_pong_loc_conf_t* lcf = NULL;
    lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ping_pong_loc_conf_t));
    if (lcf == NULL)
    {
        return NULL;
    }

    lcf->ping_pong = NGX_CONF_UNSET;

    return lcf;
}

/*
 *模块初始化时, 将阶段处理的回调函数注册进相应的阶段
 */
static ngx_int_t
ngx_http_ping_pong_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);
	
	/*每个阶段都有一个处理函数的数组, 将我们执行的函数放入数组中*/
    h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    *h = ngx_http_ping_pong_handler;

    return NGX_OK;
}
posted @ 2015-10-09 14:42  蒲蜡  阅读(1381)  评论(0编辑  收藏  举报