Nginx是一款功能强大的服务器,它可以部署出高性能的集群,它允许工程师编写出属于自己的功能模块,建议读者在编写自己的功能模块前,先对Nginx进行比较全面的了解。分享一个比较好的网盘链接:https://pan.baidu.com/s/1hs26ZZY
介绍一下我写的功能模块的背景:
这是个能通过Nginx来实时监控用户访问我们接口的功能模块,由于实际部分比较复杂,代码量比较大,现在这展示的是简化了的功能,当用户访问特定的URL时,Nginx可以通过这个功能模块捕捉到这个URL,并进行解析,判断是否应该响应用户的请求。这里并不会非常仔细地说明代码每一条代表什么意思。因为这里涉及非常多的内容,包括nginx的基本数据结构等。
首先需要注意的问题 1:
下载与安装。nginx分window版和Linux版,window版的nginx基本上是不能进行扩展的。但是直接解压就能用,也不需要安装依赖,所以它是"工具"。Linux版的不能直接用,是一堆源码,所以有一段“安装”的过程,但是正是因为如此,它才允许工程师编写自己的模块,然后跟原有的模块一起编译成工具。
Linux版本的nginx源码编译和作为工具的性质是分开的,意味着nginx源码可以编译无数次,但是作为工具只要安装一次便可,直观点描述,就是在linux系统中,源码在一个文件夹A里面,而你需要启动的nginx却是在另一个文件夹B中。当有新的模块需要添加时,你需要将自己编写的nginx代码与源码一起编译(文件夹A),生成一个新的nginx启动程序,然后把文件夹B中的nginx替换掉,第一次编译安装可以参考http://blog.csdn.net/c1481118216/article/details/77132149 。
$ sudo apt-get install gcc zlib1g-dev libpcre3 libpcre3-dev libssl-dev //下载依赖包
wget https://nginx.org/download/nginx-1.13.4.tar.gz //下载最新版nginx
$ tar -xvf nginx- 1.13 . 4 .tar.gz$ cd cd nginx- 1.13 . 4 ///解压//编译和安装,前两步是编译,最后一步是安装
$./configure
$sudo make
$sudo make install
Nginx安装好之后,会有两个地方跟Nginx相关,第一个地方是在/home/下,是我们一开始下载并解压的地方,查看有下面这些文件,它是源码。
第二个地方是在/usr/local下,有个nginx的文件夹,编译并安装好的nginx就在这里面。我们平时启动nginx就是要定位到这里。
到此其实nginx已经安装好了,我们开始编写自己的模块
需要注意的问题 2
先说明一下我们编写的模块究竟对应nginx的什么东西,首先看下图,这是nginx的配置文件nginx.conf,nginx就是通过这个文件来添加nginx的功能,这里所说的添加不是编写新的功能模块,而是将nignx已有的功能模块的开关开启,我们接着编写的功能在编译之后也将会在这里配置,才能得以使用。我们所说的自定义模块,就相当于下图中server,或是listen,或是server_name,(我们的是monitor),monitor的功能在nginx本身是不具备的,但是当我们经过一个过程之后,我们就可以在这个文件里面添加例如 :minitor mysecreepassword 这样的东西来处理用户的请求。
开始编写自己的模块
要编写属于自己的功能模块,需要编写两个文件,一个是ngx_[module_type]_[self_definition_name]_module.c和config两个文件。
基于nginx开发自定义模块,使用的文件名,是有规律的,比如说:有以下规律
ngx是固定的
module_type是nginx中的已有的模块,编译时,nginx通过识别这个段来决定你的模块应该归为哪一类
self_definition_name是自定义的,nginx通过识别这个段来决定你在nginx.conf中的指令,比如这里是monitor,所以在nginx.conf中写上
monitor xxxxxxxx就代表是我们的模块。
以下是ngx_http_monitor_module.c的内容
#include //the packages of nginx
#include
#include
static void *ngx_http_monitor_create_loc_conf(ngx_conf_t *cf);
static char * ngx_http_monitor(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_monitor_handler(ngx_http_request_t *r);
typedef struct {
ngx_str_t secret;
} ngx_http_monitor_conf_t;
static ngx_command_t ngx_http_monitor_commands[] = {
{
ngx_string("monitor"),
NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_http_monitor,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL,
},
ngx_null_command
};
static ngx_http_module_t ngx_http_monitor_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ngx_http_monitor_create_loc_conf,
NULL
};
ngx_module_t ngx_http_monitor_module = {
NGX_MODULE_V1,
&ngx_http_monitor_module_ctx,
ngx_http_monitor_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
static void *ngx_http_monitor_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_monitor_conf_t * mycf;
mycf = ngx_palloc(cf->pool, sizeof(ngx_http_monitor_conf_t));
if (mycf == NULL) {
return NGX_CONF_ERROR;
}
mycf->secret.len = 0;
mycf->secret.data = NULL;
return mycf;
}
static char * ngx_http_monitor(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_monitor_handler;
ngx_conf_set_str_slot(cf, cmd, conf);
return NGX_CONF_OK;
}
static ngx_int_t ngx_http_monitor_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_http_monitor_conf_t *mycf;
mycf = ngx_http_get_module_loc_conf(r, ngx_http_monitor_module);
ngx_int_t isAuth = 0;
ngx_str_t format = ngx_string("secret=%V");
ngx_str_t match;
match.len = format.len - 2 + mycf->secret.len;
match.data = ngx_palloc(r->pool, match.len);
ngx_snprintf(match.data, match.len, "secret=%V", &mycf->secret);
ngx_uint_t i = 0;
if (r->args.len >= match.len) {
for (; i <= r->args.len - match.len; i++) {
if (0 == ngx_strncasecmp(r->args.data + i, match.data, match.len)) {
if (i < r->args.len - match.len && *(r->args.data + i + match.len) != '&') {
continue;
}
if (i != 0 && *(r->args.data + i - 1) != '&') {
continue;
}
isAuth = 1;
break;
}
}
}
ngx_str_t response;
if (isAuth == 1) {
ngx_str_set(&response, "secret right");
} else {
ngx_str_set(&response, "secret wrong");
}
ngx_str_t type = ngx_string("text/plain");
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;
return ngx_http_output_filter(r, &out);
}
接着是conf文件,conf文件的内容比较简单
ngx_addon_name=ngx_http_monitor_module
HTTP_MODULES="$HTTP_MODULES ngx_http_monitor_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_monitor_module.c"
准备好这两个文件之后,我们定位到nginx的源码文件夹,然后执行
./configure --add-module=/usr/adtmodule/ngx_http_monitor_module
然后nginx就会开始编译你的模块,编译完之后,
执行make
需要注意的问题 3
此时注意不能执行make install,因为你已经装有一个nginx了。然后make完之后,在objs文件夹下会有一个nginx,将这个nginx替换掉原本那个/usr/local/nginx/sbin/下那个nginx。此时我们的新模块已经编写安装完毕,怎么用呢,打开/usr/local/nginx/conf/nginx.conf,然后配置如下信息
location = /monitor {
# 只有传递的secret参数值为secretpassword的时候才通过验证
# 1 通过验证页面显示“secret right”
# 2 不通过验证页面显示“secret wrong”
# 比如
# http://localhost:8080?monitor=secretpassword通过
# http://localhost:8080?monitor=123不通过
monitor secretpassword;
}
接着启动nginx
测试,我们可以得到如下结果
至此,自定义模块的编译与安装就结束了,是不是很简单?