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


static ngx_command_t ngx_http_hello_commands[] = { { ngx_string(''hello''), NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1, hello, NGX_HTTP_MAIN_CONF_OFFSET, 0, NULL }, ngx_null_command };编写指令处理函数
指令执行处理:

  • nginx 根据指令 type 字段设置的特性自动校验指令位置 , 参数个数等信息 , 并将指令语句解析为字符串数组 (类似 shell 命令行), 保存到 cf->args, 再调用指令处理函数 。
  • 指令处理函数执行成功时返回 NGX_CONF_OK, 发生错误时返回错误消息 。
  • 为了简化和统一指令处理 ,nginx 预定义了许多标准指令处理函数 , 如 ngx_conf_set_str_slot() 将一个字符串参数解析保存为一个 ngx_str_t 配置项 。
  • hello 指令可复用 ngx_conf_set_str_slot() 函数获取参数值 , 再添加额外逻辑打印 hello 语句 。
编写指令处理函数 hello() 如下:
static char* hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *str = conf; char *rv; rv = ngx_conf_set_str_slot(cf, cmd, str); if (rv != NGX_CONF_OK) { return rv; } ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, ''HELLO %V'', str); return NGX_CONF_OK; }
  • ngx_log_error() 是一个宏 , 最终将调用 ngx_log_error_core() 函数 。
  • ngx_log_error() 第 3 个参数 err 表示系统错误码 , 无对应错误码时使用 0。
  • nginx 未使用 C 标准库的 snprintf() 字符串格式化函数 , 而是自己实现了 ngx_snprintf() 函数 , 并自定义了类似的格式化字符串 , 其中 %V 表示输出 ngx_str_t * 指针指向的字符串 。
至此 , 代码开发完成 。 在 nginx 代码仓库目录下执行 make modules 重新编译生成动态模块文件 。
在配置文件 objs/nginx.conf http 配置下添加如下配置:
hello Nginx;在 nginx 代码仓库目录下执行如下命令 , nginx 日志将输出 ''HELLO Nginx'' 语句 , 按 Ctrl-C 退出 nginx。
objs/nginx -p ''$PWD'' -c objs/nginx.confHTTP 请求处理器
nginx 定义了多个 HTTP 请求处理阶段 (phase), 如读取完 HTTP 请求头后即进入 NGX_HTTP_POST_READ_PHASE 阶段 。 可在 HTTP 请求处理的各个阶段添加处理器函数 , 类似于 Java Servlet 中的 HTTP 过滤器 (Filter)。
HTTP 处理器函数签名 (函数类型) 如下:
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
  • 参数 r 为 HTTP 请求结构体 。
  • 返回值为 NGX_DECLINED 时 , 表示继续执行下一个处理器 。
  • 发生错误时 , 返回 HTTP 错误码 , 如服务器错误 500 NGX_HTTP_INTERNAL_SERVER_ERROR, nginx 将立即返回请求 。
编写 HTTP 请求处理器 hello_handler() 如下 , 对每个 HTTP 请求打印一次 hello 语句 , 同时打印解析后的请求 uri。 使用 ngx_http_get_module_main_conf() 从 HTTP 请求对象获取 ngx_http_hello_module 模块关联的配置数据 。
static ngx_int_t hello_handler(ngx_http_request_t *r) { ngx_str_t * str = ngx_http_get_module_main_conf(r, ngx_http_hello_module); ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, ''HELLO %V, uri: %V'', str, &r->uri); return NGX_DECLINED; }为 HTTP 模块编写一个 postconfiguration 函数 hello_init(), 将 HTTP 处理器 hello_handler() 注册到 NGX_HTTP_POST_READ_PHASE 阶段 。 nginx 将在完成配置解析 (执行完配置指令) 后执行 HTTP 模块的 postconfiguration 函数 , 以完成模块初始化 。
static ngx_int_t 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_POST_READ_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } *h = hello_handler; return NGX_OK; }更新 ngx_http_module_t ngx_http_hello_module_ctx, 设置 postconfiguration 为 hello_init() 函数 。


推荐阅读