nginx中handle模块的编写小案例

简介: nginx中handle模块的编写小案例

nginx源码中是可以自己添加自定义的模块的,自己需要一些自定义的功能,可以自己实现一个模块。

  1. 编写自己模块的具体实现
  2. 编写自己模块的config 配置文件
  3. 将自己的模块加入到nginx config配置中 , 编译和安装nginx
  4. 修改nginx.conf文件,将自己添加的模块关键字写入到配置文件中
  5. 启动nginx,查看效果

 

举一个例子:

需求:现在我们来实现一个功能,来记录不同ip访问nginx的次数

最后实现的ngx_http_pagecount_module模块目录结构如下

 

编写自己模块的具体实现

ngx_http_pagecount_module.c

#include <ngx_http.h>
#include <ngx_config.h>
#include <ngx_core.h>
/*
#include <arpa/inet.h>
#include <netinet/in.h>
*/
#define ENABLE_RBTREE 1
static char *ngx_http_count_module_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_count_module_handler(ngx_http_request_t *r);
static ngx_command_t count_commands[] = {
  {
    ngx_string("count"),
    NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
    ngx_http_count_module_set,
    NGX_HTTP_LOC_CONF_OFFSET,
    0, NULL
  },
  ngx_null_command
};
static ngx_http_module_t count_ctx = {
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
};
//ngx_http_count_module 
ngx_module_t ngx_http_count_module = {
  NGX_MODULE_V1,
  &count_ctx,
  count_commands,
  NGX_HTTP_MODULE,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NGX_MODULE_V1_PADDING
};
typedef struct {
  int count; //count
  struct in_addr addr; //ip
} ngx_pv_table;
ngx_pv_table pv_table[256];
#if ENABLE_RBTREE
ngx_rbtree_t ngx_pv_tree;
ngx_rbtree_node_t sentinel;
static void
ngx_pagecount_rbtree_insert_value(ngx_rbtree_node_t *temp,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t    **p;
    for ( ;; ) {
        if (node->key < temp->key) {
            p = &temp->left;
        } else if (node->key > temp->key) {
            p = &temp->right;
        } else { /* node->key == temp->key */
            return ;
        }
        if (*p == sentinel) {
            break;
        }
        temp = *p;
    }
    *p = node;
    node->parent = temp;
    node->left = sentinel;
    node->right = sentinel;
    ngx_rbt_red(node);
}
#endif
static char *ngx_http_count_module_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
#if ENABLE_RBTREE
  ngx_rbtree_init(&ngx_pv_tree, &sentinel, ngx_pagecount_rbtree_insert_value);
#endif
  ngx_http_core_loc_conf_t *corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  corecf->handler = ngx_http_count_module_handler;
  return NGX_CONF_OK;
}
#if ENABLE_RBTREE
//char content[1024];
void ngx_http_count_rbtree_iterator(ngx_rbtree_node_t *node, char *html) {
  char buffer[128] = {0};
  struct in_addr addr = {0};
  memcpy(&addr, &node->key, sizeof(struct in_addr));
  sprintf(buffer, "req from : %s, count: %d <br/>",
    inet_ntoa(addr), node->value);
  strcat(html, buffer);
}
static int ngx_encode_http_page_rb(char *html) {
  sprintf(html, "<h1>Source Insight </h1>");
  strcat(html, "<h2>");
  ngx_rbtree_traversal(&ngx_pv_tree, ngx_pv_tree.root, ngx_http_count_rbtree_iterator, html);
  strcat(html, "</h2>");
  return 0;
}
#else
#if 1
static int ngx_encode_http_page(char *html) {
  sprintf(html, "<h1>Source Insight </h1>");
  strcat(html, "<h2>");
  int i = 0;
  for (i = 0;i < 256;i ++) {
    if (pv_table[i].count != 0) {
      char str[INET_ADDRSTRLEN] = {0};
      char buffer[128] = {0};
      sprintf(buffer, "req from : %s, count: %d <br/>",
        inet_ntop(AF_INET, &pv_table[i].addr, str, sizeof(str)), pv_table[i].count);
      strcat(html, buffer);
    }
  }
  strcat(html, "</h2>");
  return 0;
}
#endif
#endif
static ngx_int_t ngx_http_count_module_handler(ngx_http_request_t *r) {
#if 0
  u_char html[1024] = "<h1> bailang, Reese, feifei, qizhewoniuqukandahai, huihuisasa, magic, jianyuebujiandan, yuan </h1>";
  int len = sizeof(html);
#elif 1
  u_char html[1024] = {0};
  int len = sizeof(html);
#if ENABLE_RBTREE
  ngx_rbtree_node_t *node = NULL;
  ngx_rbtree_key_t key = 0;
#endif
  struct sockaddr_in *client_addr =  (struct sockaddr_in*)r->connection->sockaddr;
  //rbtree <key, value>  --> <addr, count>
  int idx = client_addr->sin_addr.s_addr >> 24;
  //rbtree --> (key, value)
  pv_table[idx].count ++;
  memcpy(&pv_table[idx].addr, &client_addr->sin_addr, sizeof(client_addr->sin_addr));
#if ENABLE_RBTREE
  key = (ngx_rbtree_key_t)client_addr->sin_addr.s_addr;
  ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, " ngx_http_count_module_handler --> %x\n", key);
  node = ngx_rbtree_search(&ngx_pv_tree, key);
  ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, " 11111 --> %x\n", key);
  if (node == &sentinel) {
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, " new node insert rbtree\n", key);
    node = ngx_pcalloc(r->pool, sizeof(ngx_rbtree_node_t));
    node->key = (ngx_rbtree_key_t)client_addr->sin_addr.s_addr;
    node->value = 1;
    ngx_rbtree_insert(&ngx_pv_tree, node);
  } else {
    node->value ++;
    ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, " node is exist, value:%d\n", node->value);
  }
  //memset(content, 0, 1024);
  ngx_encode_http_page_rb((char*)html);
  ngx_log_error(NGX_LOG_EMERG, r->connection->log, ngx_errno, " html: %s\n", html);
  //memcpy(html, content, len);
#else
  ngx_encode_http_page((char*)html);
#endif
#else
  struct sockaddr_in *client_addr =  (struct sockaddr_in*)r->connection->sockaddr;
  ngx_rbtree_node_t *node = ngx_pcalloc(r->pool,  sizeof(ngx_rbtree_node_t));
  memcpy(&node->key, &client_addr->sin_addr.s_addr, sizeof(node->key));
#endif
  //header
  r->headers_out.status = 200;
  ngx_str_set(&r->headers_out.content_type, "text/html");
  ngx_http_send_header(r);
  //body
  ngx_buf_t *b = ngx_pcalloc(r->pool,  sizeof(ngx_buf_t));
  ngx_chain_t out;
  out.buf = b;
  out.next = NULL;
  b->pos = html;
  b->last = html+len;
  b->memory = 1;
  b->last_buf = 1;
  return ngx_http_output_filter(r, &out);
}

 

编写自己模块的config 配置文件

config

ngx_addon_name=ngx_http_pagecount_module
HTTP_MODULES="$HTTP_MODULES ngx_http_pagecount_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/pagecount_module.c"

将自己的模块加入到nginx config配置中

编译和安装nginx

大家可以下载nginx-1.13.7版本的nginx进行添加和验证

nginx下载地址: http://nginx.org/en/download.html

#配置  添加模块的时候写 模块的绝对路径
./configure  --add-module=/home/qb/software/nginx-1.13.7_study/ngx_http_pagecount_module
#编译
make
#安装
make install

 

修改nginx.conf文件,将自己添加的模块关键字写入到配置文件中

将自己的模块关键字 写入到配置文件中

启动nginx,查看效果

#启动nginx
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

 

相关文章
|
1月前
|
应用服务中间件 nginx
Nginx安装nginx-rtmp-module模块
【2月更文挑战第4天】 nginx中的模块虽然就是类似插件的概念,但是它无法像VsCode那样轻松的安装扩展。 nginx要安装其它模块必须同时拿到nginx源代码和模块源代码,然后手动编译,将模块打到nginx中,最终生成一个名为nginx的可执行文件。
77 6
|
3月前
|
应用服务中间件 nginx
百度搜索:蓝易云【利用nginx内置ngx_http_mirror_module模块实现流量复制及流量放大】
以上就是使用Nginx内置 `ngx_http_mirror_module`模块实现流量复制和流量放大的简要示例。通过合理配置和利用该模块,可以实现更复杂的流量控制和调试需求。
58 1
|
7月前
浅谈基于openresty(nginx+lua)开发轻量级,按流量控制的灰度模块(下)
浅谈基于openresty(nginx+lua)开发轻量级,按流量控制的灰度模块
80 0
|
30天前
|
应用服务中间件 Linux PHP
Linux下安装php环境并且配置Nginx支持php-fpm模块
Linux下安装php环境并且配置Nginx支持php-fpm模块
29 0
|
2月前
|
消息中间件 关系型数据库 MySQL
使用Nginx的stream模块实现MySQL反向代理与RabbitMQ负载均衡
使用Nginx的stream模块实现MySQL反向代理与RabbitMQ负载均衡
64 0
|
3月前
|
存储 应用服务中间件 nginx
Nginx模块开发:handler模块实现
Nginx模块开发:handler模块实现
29 0
|
3月前
|
存储 应用服务中间件 nginx
Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现
Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现
65 0
|
3月前
|
存储 应用服务中间件 nginx
Nginx:过滤模块的实现
Nginx:过滤模块的实现
|
3月前
|
存储 负载均衡 网络协议
Nginx: handler 模块的实现
Nginx: handler 模块的实现
|
3月前
|
前端开发 应用服务中间件 nginx
nginx过滤器模块
nginx过滤器模块