|零基础开发 nginx 模块( 四 )


我最早学习使用的是 Apache HTTP 服务器 , 其至今仍然是一款优秀强大的开源软件 。 一些团队因为特殊原因开始尝试新产品 , 俄罗斯程序员 Igor Sysoev 开发的 nginx 很快因其稳定性和高性能而声名鹊起 。
最初学习使用 nginx 的感受是 , nginx 的配置文件似乎比 apache 要简单友好一些 (在我对两者都不熟悉的情况下)。 nginx 的配置文件好像是一种脚本 , 所以 nginx 配置项被称作指令 (directive)。 没错 , nginx 不只是一个 HTTP 服务器 , 还是一个被设计得简单小巧的脚本语言解释器 , 并支持开发添加新的指令 。 nginx 指令通常用于配置 , 我们称之为配置指令 , 换一种唬人的说法 , 叫做声明式指令 。
现在我们设计一个 hello 指令输出 ''hello world'' 语句 。
创建配置存储结构体
HTTP 配置分为 http/server/location 3 层结构 。 我们设计 hello 指令仅在最顶层 http {} 主区块 (block) 下使用和生效 。 HTTP 模块默认无配置存储空间 , 可设置 ngx_http_module_t::create_main_conf 函数创建主区块配置结构体 。
我们设计本模块仅包含一个字符串参数 , 即要输出的语句 。 nginx 字符串类型为 ngx_str_t, 编写创建主配置结构体的函数 hello_create_main_conf() 如下:
static void* hello_create_main_conf(ngx_conf_t *cf) { ngx_str_t *conf; conf = ngx_pcalloc(cf->pool, sizeof(ngx_str_t)); if (conf == NULL) { return NULL; } return conf; }

  • 从配置内存池 cf->pool 分配一个字符串 ngx_str_t, 分配结构体将初始化为 0, 对 ngx_str_t 即空字符串 。
  • 如果函数返回 NULL 则表示分配失败, nginx 将报错退出 。
更新 ngx_http_module_t ngx_http_hello_module_ctx, 设置 create_main_conf 为 hello_create_main_conf() 函数 。
static ngx_http_module_t ngx_http_hello_module_ctx = { NULL,/* preconfiguration */ NULL,/* postconfiguration */ hello_create_main_conf,/* create main configuration */ NULL,/* init main configuration */ NULL,/* create server configuration */ NULL,/* merge server configuration */ NULL,/* create location configuration */ NULL/* merge location configuration */ };创建指令
一个指令用一个 ngx_command_t 类型的数据结构表示 。
typedef struct ngx_command_sngx_command_t; struct ngx_command_s { ngx_str_tname; ngx_uint_ttype; char*(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_uint_tconf; ngx_uint_toffset; void*post; }; #define ngx_null_command{ ngx_null_string, 0, NULL, 0, 0, NULL }
  • name 指定指令名 , 如 hello。
  • type 是一个混合结构 , 包含指令类型、指令使用位置、指令参数个数等多种特性信息 。 使用 NGX_HTTP_MAIN_CONF 表示指令可在 http 主配置使用 , NGX_CONF_TAKE1 表示指令接受 1 个参数 。
  • set 为指令处理函数 , 即 nginx 配置设置函数 。
  • conf 指示保存配置结构体的位置 。 使用 NGX_HTTP_MAIN_CONF_OFFSET 表示指令配置在 http 主配置下存储生效 。
  • offset 指示指令配置字段的位置 。 通常一个模块的配置是一个结构体 , 而一个指令的配置是其中一个字段 , set 函数通过 offset 访问字段 , 这样不需要知道结构体的类型 (结构) , 就可以读写配置字段 。 模块只有一个配置项时 , 设置为 0 即可 。
  • post 对特定处理函数可增加后置处理函数 , 或增加传入参数 。 通常不使用 , 设为 NULL。
声明指令处理函数 hello() :
static char* hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);创建 hello 指令如下:


推荐阅读