戏说nginx模块开发之Hello world

(为了让流程更清晰,我删掉了各种错误处理与返回值判断等等,实际中还是要判断判断滴)

1、先看处理请求的handler,不是智障应该都能看懂:


static ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r) 
{
        //丢弃掉请求的body
        ngx_http_discard_request_body(r);
 
        ngx_str_t response = ngx_string("Hello world");
         
        //分配内存,因为是异步的关系,所以不能发送栈区内存中的数据
        //否则栈被析构了请求还没发,等框架准备好了再来发的时候,那块内存就已经不是“Hello world”了
        ngx_buf_t* b;
        b = ngx_create_temp_buf(r->pool, response.len);
        ngx_memcpy(b->pos, response.data, response.len);
         
        //以下步骤是必须的,否则不会发送任何相应
        b->last = b->pos + response.len;
        b->last_buf = 1;
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_length_n = response.len;
 
        ngx_http_send_header(r);
         
        //一个ngx_buf_t的链表
        ngx_chain_t out;
        out.buf = b;
        out.next = NULL;
 
        return ngx_http_output_filter(r, &out);
}

那么问题来了,这tmd怎么被调用的?

static ngx_int_t ngx_http_hello_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);
        
        //在模块内容被解析的时候,会有一个函数链(handlers)被挨个调用,我们把上面那玩意儿
        //加到这个handlers里面去就行了。
        
        h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);  
        if (h == NULL) {
             return NGX_ERROR;        
        }
        //改变函数指针的值        
        *h = ngx_http_hello_handler;  
              
        return NGX_OK;
}
static ngx_http_module_t ngx_http_hello_module_ctx = { 
        NULL,                          /* preconfiguration */
        ngx_http_hello_init,           /* postconfiguration */
        NULL,                          /* create main configuration */
        NULL,                          /* init main configuration */
        NULL,                          /* create server configuration */
        NULL,                          /* merge server configuration */
        ngx_http_hello_create_loc_conf, /* create location configuration */
        NULL                            /* merge location configuration */
};

看博客的你心想:“凭借哥180的智商断定这函数是在解析完配置文件被调用的!”,笔者为阁下有

如此高的领悟力深感欣慰!   

此配置就是在框架初始化时的八个回调函数。

前戏太长,看博客的你可能心里不太耐烦了,话不多说让咱看看配置文件:

location /test {
    hello_string Hello world;
}

咱的目的:访问  ip/test时输出hello world。框架如何解析hello_string配置项的?

static ngx_command_t ngx_http_hello_commands[] = {
   {
        ngx_string("hello_string"),  //模块名称
        NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, //location级别内,不带参数,或者带一个参数
        ngx_http_hello_string,     //解析配置文件的方法
        NGX_HTTP_LOC_CONF_OFFSET,   
        offsetof(ngx_http_hello_loc_conf_t, hello_string),
        NULL 
    },  
    ngx_null_command
};

我们有了上下文,也有了命令,接下来就要定义模块了,让他们形成漂亮的3p:

ngx_module_t ngx_http_hello_module = {
        NGX_MODULE_V1,
        &ngx_http_hello_module_ctx,    /* module context */
        ngx_http_hello_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
};

哥尼玛日了狗了,两函数差点没看懂,搞配置文件的俩函数(差点因为这俩函数b都装不成了)

咱输出Hello world不太需要处理配置文件,后面详解配置模块:

static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
        //为配置文件信息分配存储结构,没有这玩意儿可能会段错误哟亲
        ngx_http_hello_loc_conf_t* local_conf = NULL;
        local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
        if (local_conf == NULL)
        {
                return NULL;
        }

        ngx_str_null(&local_conf->hello_string);

        //返回分配好的结构
        return local_conf;
}
    
static char *
ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{   
        ngx_http_hello_loc_conf_t* local_conf;
        
        //conf就里就是配置块的信息。
        local_conf = conf;
        //获取字符串类型的参数
        char* rv = ngx_conf_set_str_slot(cf, cmd, conf);
        
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data);
        
        return rv;
}

好了,可以编译我们的模块了

$mkdir  nginx-module
$cd nginx-module
$touch ngx_http_mytest_module.c   config

福利,完整的.c文件代码:

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

typedef struct
{
        ngx_str_t hello_string;
}ngx_http_hello_loc_conf_t;

static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf);

static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf);

static char *ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd,
        void *conf);

        
static ngx_command_t ngx_http_hello_commands[] = {
   {
        ngx_string("hello_string"),
        NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
        ngx_http_hello_string,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_hello_loc_conf_t, hello_string),
        NULL
    },
    ngx_null_command
};

static ngx_http_module_t ngx_http_hello_module_ctx = {
        NULL,                          /* preconfiguration */
        ngx_http_hello_init,           /* postconfiguration */

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

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

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

ngx_module_t ngx_http_hello_module = {
        NGX_MODULE_V1,
        &ngx_http_hello_module_ctx,    /* module context */
        ngx_http_hello_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_hello_handler(ngx_http_request_t *r)
{
        ngx_http_discard_request_body(r);

        ngx_str_t response = ngx_string("Hello world");

        ngx_buf_t* b;
        b = ngx_create_temp_buf(r->pool, response.len);
        ngx_memcpy(b->pos, response.data, response.len);
        b->last = b->pos + response.len;
        b->last_buf = 1;
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_length_n = response.len;
        ngx_http_send_header(r);

        ngx_chain_t out;
        out.buf = b;
        out.next = NULL;

        return ngx_http_output_filter(r, &out);
}

static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
        ngx_http_hello_loc_conf_t* local_conf = NULL;
        local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
        if (local_conf == NULL)
        {
                return NULL;
        }

        ngx_str_null(&local_conf->hello_string);

        return local_conf;
}

static char *
ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
        ngx_http_hello_loc_conf_t* local_conf;

        local_conf = conf;
        char* rv = ngx_conf_set_str_slot(cf, cmd, conf);

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data);

        return rv;
}

static ngx_int_t
ngx_http_hello_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_hello_handler;

        return NGX_OK;
}

哥复制粘贴这么累,你不点个赞对的起我?

config文件,模块的名称,源文件名:

ngx_add_name=ngx_http_hello_module                                        
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"                        
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

找到你nginx源码的目录(你不要傻不拉唧的真写yourpath):

$./configure --add-module=yourpath/nginx-module/  && make && make install

一般安装目录在/usr/local/nginx下面

修改配置文件:

$vim /usr/local/nginx/conf/nginx.conf

location /test{
    hello_string sb;
}

运行nginx:

$/usr/local/nginx/sbin/nginx

浏览器访问:

另:

在gdb调试handler的时候,要去调试worker进程

$ps -aux|grep nginx
$gdb
...)attach nginx_worker_pid
...)b XXX_handler   
...)c                           //发送请求后执行c命令
时间: 2024-12-25 08:11:55

戏说nginx模块开发之Hello world的相关文章

Magento 模块开发之DispatchEvent

在这一章节中,我们来了解 Magento 中的事件分发机制 Mage::dispatchEvent() 在创建自己的模块时, Event 事件的分发将会变成十分有用且有效 以个人的经验, 事件的分发使用频率应该高于对类的重写(overriding), 为什么这么说呢, 当有多个模块的时候, 重写同一个类(class)时,那它们互相将会有冲突, 只有一个模块将会正常工作, 但是如果你使用事件的话, 那么多个模块都可以很轻松的去调用它 Magento 中的事件也是根据观察者(Observer)设计模

Magento 模块开发之DispatchEvent(转)

在这一章节中,我们来了解 Magento 中的事件分发机制 Mage::dispatchEvent()在创建自己的模块时, Event 事件的分发将会变成十分有用且有效 以个人的经验, 事件的分发使用频率应该高于对类的重写(overriding), 为什么这么说呢, 当有多个模块的时候, 重写同一个类(class)时,那它们互相将会有冲突, 只有一个模块将会正常工作, 但是如果你使用事件的话, 那么多个模块都可以很轻松的去调用它 Magento 中的事件也是根据观察者(Observer)设计模式

具体解释EBS接口开发之WIP模块接口

整体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对採用并发请求方式和调用API方式分别进行介绍 内容 WIP模块经常使用标准表简单介绍 WIP事物处理组成 WIP相关业务流程 WIP相关API研究事例 (十)參考文档(七)採购相关的一些知识 (一)WIP模块经常使用标准表简单介绍 1.1   经常使用标准表 例如以下表中列出了与WIP导入相关的表和说明: 表名 说明 其它信息 BOM_STRUCTURES_B BOM头信息 BOM_COMPONENTS_B BOM组件信息

iOS开发之Socket通信实战--Request请求数据包编码模块

实际上在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socket网络协议进行网络数 据传输,这时候在iOS客户端就需要很好的第三方CocoaAsyncSocket来进行长连接连接和传输数据,该第三方地 址:https://github.com/robbiehanson/CocoaAsyncSocket,读者可以自行google或者baidu搜索 这个库的用法,网上有很多资料,而且用法不难. 在一些对Socket通信使用需求不是很高的应用中,比如需要

Asp.net模块化开发之“部分版本部分模块更新(上线)”

项目开发从来就不是一个简单的问题.更难的问题是维护其他人开发的项目,并且要修改bug.如果原系统有重大问题还需要重构. 怎么重构系统不是本文探讨的问题,但是重构后如何上线部署和本文关系密切.这个大家可能刚兴趣. 言归正传,现在演示一下如果做到部分版本和部分模块更新. Asp.net模块化开发系列目录 1. Asp.net模块化开发之Mvc分区扩展框架(送源码) 2. Asp.net模块化开发之“开启分模块开发简单愉快之旅” 3. Asp.net模块化开发之“逻辑(项目)复用” 3.1. 不同角色

详解EBS接口开发之WIP模块接口

总体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对采用并发请求方式和调用API方式分别进行介绍 内容 WIP模块常用标准表简介 WIP事物处理组成 WIP相关业务流程 WIP相关API研究事例 (十)参考文档(七)采购相关的一些知识 (一)WIP模块常用标准表简介 1.1   常用标准表 如下表中列出了与WIP导入相关的表和说明: 表名 说明 其他信息 BOM_STRUCTURES_B BOM头信息 BOM_COMPONENTS_B BOM组件信息 BOM_OPERATIO

[原]零基础学习SDL开发之在Android使用SDL2.0显示BMP图

关于如何移植SDL2.0到安卓上面来参考我的上一篇文章:[原]零基础学习SDL开发之移植SDL2.0到Android 在一篇文章我们主要使用SDL2.0来加载一张BMP图来渲染显示. 博主的开发环境:Ubuntu 14.04 64位,Eclipse + CDT + ADT+NDK 博主曾经自己使用NDK编译出了libSDL2.so,然后使用共享库的方式来调用libSDL2中的函数,结果发现SDL\src\core\android\SDL_android.c 这个jni函数写的实在是不够自己另外做

监控开发之用munin来自定义插件监控redis和mongodb

求监控组的大哥大妹子们干点事,真不容易 ! 要问他们是谁?  他们是神 .轻易别找他们,因为找了也是白找. 上次因为python和redis长时间brpop的时候,会有线程休眠挂起的情况,所有通知报警平台被下线了.这次算是完美解决了.再把他给上线.这两公司的告警已经开始往我这边的接口开始仍了. 这边正在改zabbix cmdb的控制,所以暂时不能登录.等搞好了后,让他们搞下redis和mogodb的监控,居然还让我发邮件和提供脚本及思路啥的...   一寻思,又要去zabbix,又要写脚本,还不

linux下nginx模块开发入门

本文模块编写参考http://blog.codinglabs.org/articles/intro-of-nginx-module-development.html 之前讲了nginx的安装,算是对nginx有了最初步的了解,在配置完之后,我们就可以进行简单的nginx模块开发了. 下面本文展示一个简单的Nginx模块开发全过程,我们开发一个叫echo的handler模块,这个模块功能非常简单,它接收“echo”指令,指令可指定一个字符串参数,模块会输出这个字符串作为HTTP响应.例如,对ngi