设为首页 收藏本站
查看: 1271|回复: 6

[经验分享] Nginx模块开发入门学习

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2013-7-5 08:44:48 | 显示全部楼层 |阅读模式

这里主要通过一个简单的 hello world 示例学习一下 nginx 中 http 模块(Nginx 还支持 event 模块,mail模块等)开发。


我们下面就是开发一个名叫 mytest 的模块,该模块很简单,就是输出 hello world!,如下配置:


   location /mytest {

       ngx_mytest_module;

   }


当访问 curl -i http://localhost:38080/mytest 时输出如下:


[iyunv@dev nginx]# curl -i http://localhost:38080/mytest

HTTP/1.1 200 OK

Server: nginx/1.4.1

Date: Thu, 04 Jul 2013 07:26:49 GMT

Content-Type: text/plain

Content-Length: 13

Connection: keep-alive


hello, world!


1,定义指令


/* Commands */

static ngx_command_t  ngx_http_mytest_commands[] = {

   { ngx_string("ngx_mytest_module"),

     NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

     ngx_http_mytest,

     NGX_HTTP_LOC_CONF_OFFSET,

     0,

     NULL },


   ngx_null_command

};


这里定义了指令名为 ngx_mytest_module。其中 ngx_command_t 的结构定义如下:


struct ngx_command_s {

   ngx_str_t             name;

   ngx_uint_t            type;

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

   ngx_uint_t            conf;

   ngx_uint_t            offset;

   void                 *post;

};


   - name:指令名

   - type:使用掩码位方式配置指令参数,可用配置 types 定义在 core/ngx_conf_file.h 和 http/ngx_http_config.h 中,如下:


------------------------

core/ngx_conf_file.h


#define NGX_CONF_NOARGS      0x00000001

#define NGX_CONF_TAKE1       0x00000002

#define NGX_CONF_TAKE2       0x00000004

#define NGX_CONF_TAKE3       0x00000008

#define NGX_CONF_TAKE4       0x00000010

#define NGX_CONF_TAKE5       0x00000020

#define NGX_CONF_TAKE6       0x00000040

#define NGX_CONF_TAKE7       0x00000080


#define NGX_CONF_ARGS_NUMBER 0x000000ff

#define NGX_CONF_BLOCK       0x00000100

#define NGX_CONF_FLAG        0x00000200

#define NGX_CONF_ANY         0x00000400

#define NGX_CONF_1MORE       0x00000800

#define NGX_CONF_2MORE       0x00001000

#define NGX_CONF_MULTI       0x00000000  /* compatibility */


#define NGX_DIRECT_CONF      0x00010000


#define NGX_MAIN_CONF        0x01000000

#define NGX_ANY_CONF         0x0F000000


------------------------

http/ngx_http_config.h


#define NGX_HTTP_MAIN_CONF        0x02000000

#define NGX_HTTP_SRV_CONF         0x04000000

#define NGX_HTTP_LOC_CONF         0x08000000

#define NGX_HTTP_UPS_CONF         0x10000000

#define NGX_HTTP_SIF_CONF         0x20000000

#define NGX_HTTP_LIF_CONF         0x40000000

#define NGX_HTTP_LMT_CONF         0x80000000


   - set 函数指针,用于指定一个参数转化函数,一般主要用于将配置文件中的相关指令参数转化成需要的格式并存入配置结构体中,因我的示例里没有参数,只是简单的注册了 handler 函数指针


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

{

       ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, \

                                               ngx_http_core_module);

       fprintf(stderr, "ngx_http_mytest pid=%d\n", getpid());


       /* register hanlder */

       clcf->handler = ngx_http_mytest_handler;


       return NGX_CONF_OK;

}


2,定义模块 Context


static ngx_http_module_t  ngx_http_mytest_module_ctx = {

       NULL,           /* preconfiguration */

       NULL,           /* postconfiguration */


       NULL,           /* create main configuration */

       NULL,           /* init main configuration */


       NULL,           /* create server configuration */

       NULL,           /* merge server configuration */


       NULL,           /* create location configration */

       NULL            /* merge location configration */

};


3,编写 Handler


handler 一般主要有 4 个职责:


   - 读入模块配置

   - 处理业务功能

   - 生成 HTTP Header

   - 生成 HTTP Body


static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)

{

   if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))

   {

       return NGX_HTTP_NOT_ALLOWED;

   }


   ngx_int_t rc = ngx_http_discard_request_body(r);

   if (rc != NGX_OK)

   {

       return rc;

   }


   ngx_str_t type = ngx_string("text/plain");

   ngx_str_t response = ngx_string("hello, world!");

   r->headers_out.status = NGX_HTTP_OK;

   r->headers_out.content_length_n = response.len;

   r->headers_out.content_type = type;


   // 发送响应头

   rc = ngx_http_send_header(r);

   if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)

   {

       return rc;

   }


   // 生成响应体

   ngx_buf_t *b;

   b = ngx_create_temp_buf(r->pool, response.len);

   if (b == NULL)

   {

       return NGX_HTTP_INTERNAL_SERVER_ERROR;

   }


   ngx_memcpy(b->pos, response.data, response.len);

   b->last = b->pos + response.len;

   b->last_buf = 1;


   ngx_chain_t out;

   out.buf = b;

   out.next = NULL;


   // 通过 filter 输出(缓冲区中的)响应

   return ngx_http_output_filter(r, &out);

}


对上面用到的几个重要数据结构简单了解了一下:


   1) handler 接收到的 http 请求消息结构定义(ngx_http_request_t,定义于 http/ngx_http_request.h):


struct ngx_http_request_s {

   uint32_t                          signature;         /* "HTTP" */


   ngx_connection_t                 *connection;


   void                            **ctx;

   void                            **main_conf;

   void                            **srv_conf;

   void                            **loc_conf;


   ngx_http_event_handler_pt         read_event_handler;

   ngx_http_event_handler_pt         write_event_handler;


#if (NGX_HTTP_CACHE)

   ngx_http_cache_t                 *cache;

#endif


   ngx_http_upstream_t              *upstream;

   ngx_array_t                      *upstream_states;

                                        /* of ngx_http_upstream_state_t */


   ngx_pool_t                       *pool;

   ngx_buf_t                        *header_in;


   ngx_http_headers_in_t             headers_in;

   ngx_http_headers_out_t            headers_out;


   ngx_http_request_body_t          *request_body;


   time_t                            lingering_time;

   time_t                            start_sec;

   ngx_msec_t                        start_msec;


   ngx_uint_t                        method;

   ngx_uint_t                        http_version;


   ngx_str_t                         request_line;

   ngx_str_t                         uri;

   ngx_str_t                         args;

   ngx_str_t                         exten;

   ngx_str_t                         unparsed_uri;


   ngx_str_t                         method_name;

   ngx_str_t                         http_protocol;


   ngx_chain_t                      *out;

   ngx_http_request_t               *main;

   ngx_http_request_t               *parent;

   ngx_http_postponed_request_t     *postponed;

   ngx_http_post_subrequest_t       *post_subrequest;

   ngx_http_posted_request_t        *posted_requests;


   ngx_int_t                         phase_handler;

   ngx_http_handler_pt               content_handler;

   ngx_uint_t                        access_code;


   ngx_http_variable_value_t        *variables;


#if (NGX_PCRE)

   ngx_uint_t                        ncaptures;

   int                              *captures;

   u_char                           *captures_data;

#endif


   size_t                            limit_rate;


   /* used to learn the Apache compatible response length without a header */

   size_t                            header_size;


   off_t                             request_length;


   ngx_http_upstream_t              *upstream;

   ngx_array_t                      *upstream_states;

                                        /* of ngx_http_upstream_state_t */


   ngx_pool_t                       *pool;

   ngx_buf_t                        *header_in;


   ngx_http_headers_in_t             headers_in;

   ngx_http_headers_out_t            headers_out;


   ngx_http_request_body_t          *request_body;


   ... ...

}


   这个请求结构爆长(超过110个成员变量),只列出了部分,可以通过这个结构访问 url,args,request_body等等常见 HTTP 信息。而这里还需要注意 headers_in,headers_out 和 chain 等字段,它们分别用于表示 request_header,response header 以及 输出数据缓冲区链表。


   2) 在返回 HTTP 响应时主要是设置 headers_out 字段来实现,我们示例只设置了 Content-Type 和 Content-Length 等基本信息,headers_out 类型 ngx_http_headers_out_t 还定义了其他字段:


typedef struct {

   ngx_list_t                        headers;


   ngx_uint_t                        status;

   ngx_str_t                         status_line;


   ngx_table_elt_t                  *server;

   ngx_table_elt_t                  *date;

   ngx_table_elt_t                  *content_length;

   ngx_table_elt_t                  *content_encoding;

   ngx_table_elt_t                  *location;

   ngx_table_elt_t                  *refresh;

   ngx_table_elt_t                  *last_modified;

   ngx_table_elt_t                  *content_range;

   ngx_table_elt_t                  *accept_ranges;

   ngx_table_elt_t                  *www_authenticate;

   ngx_table_elt_t                  *expires;

   ngx_table_elt_t                  *etag;


   ngx_str_t                        *override_charset;


   size_t                            content_type_len;

   ngx_str_t                         content_type;

   ngx_str_t                         charset;

   u_char                           *content_type_lowcase;

   ngx_uint_t                        content_type_hash;


   ngx_array_t                       cache_control;


   off_t                             content_length_n;

   time_t                            date_time;

   time_t                            last_modified_time;

} ngx_http_headers_out_t;


   设置好响应头信息后,可以通过 ngx_http_send_header 来输出头信息。


   3) 下面就是要发送响应body,这里主要涉及了 ngx_chain_t 结构:


struct ngx_chain_s {

   ngx_buf_t    *buf;

   ngx_chain_t  *next;

};

   看结构,可以知道 ngx_chain_t 就是一个单链表,每个节点是 ngx_chain_t 类型,而 buf 为指向实际数据的缓冲区指针,ngx_buf_t 结构定义如下:


struct ngx_buf_s {

   u_char          *pos;

   u_char          *last;

   off_t            file_pos;

   off_t            file_last;


   u_char          *start;         /* start of buffer */

   u_char          *end;           /* end of buffer */

   ngx_buf_tag_t    tag;

   ngx_file_t      *file;

   ngx_buf_t       *shadow;


   ... ...


   /* STUB */ int   num;

};


   这里用到主要是 pos 和 last 指针,分别表示数据在缓冲区中的起始地址与结束地址。如例子中的数据 "hello, world!"。


   4) 下面就是通过 filter 遍历指定的链表(ngx_chain_t)来输出响应体内容


4,组合 Module


ngx_module_t ngx_http_mytest_module = {

   NGX_MODULE_V1,

   &ngx_http_mytest_module_ctx,    /* module context */

   ngx_http_mytest_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

};


5,模块的编译安装


   1) 模块 config 文件,该文件需要与模块源文件放在同一路径下,如下:


[iyunv@dev ngx_http_mytest]# ll

总用量 8

-rw-r--r--. 1 root root  164 2013-07-04 10:39 config

-rw-r--r--. 1 root root 2521 2013-07-04 15:17 ngx_http_mytest_module.c

[iyunv@dev ngx_http_mytest]#

[iyunv@dev ngx_http_mytest]# more config

ngx_addon_name=ngx_http_mytest_module

HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"

NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"


   2) 进入 Nginx 源码路径,使用下面命令编译安装:


   ./configure --prefix=/root/apps/nginx --add-module=/root/test/ngx_http_mytest

   make

   sudo make install


参考资料:


nginx 模块开发向导:http://www.evanmiller.org/nginx-modules-guide.html

可以参考学习的第三方模块:http://wiki.nginx.org/3rdPartyModules

Nginx 模块开发入门:http://kb.iyunv.com/page/98352/




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-7037-1-1.html 上篇帖子: nginx的configure参数 下篇帖子: nginx+php-fpm+xcache 开发

尚未签到

发表于 2013-7-5 13:37:31 | 显示全部楼层
月经不仅仅是女人的痛苦,也是男人的痛苦。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

尚未签到

发表于 2013-7-6 07:49:37 | 显示全部楼层
不在课堂上沉睡,就在酒桌上埋醉。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

尚未签到

发表于 2013-7-6 08:35:57 | 显示全部楼层
精典之极就是精斑!!!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

尚未签到

发表于 2013-7-6 12:25:09 | 显示全部楼层
要是我灌水,就骂我“三个代表”没学好吧。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

尚未签到

发表于 2013-7-6 19:55:54 | 显示全部楼层
禽兽尚且有半点怜悯之心,而我一点也没有,所以我不是禽兽。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

尚未签到

发表于 2013-7-6 21:23:14 | 显示全部楼层
为中华而努力读书!一包中华好多钱啊~~~

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表