Linux下Nginx自定义模块开发

来源:互联网 发布:linux权限管理命令 编辑:程序博客网 时间:2024/05/16 01:25

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$cdcd 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 <ngx_config.h> //the packages of nginx#include <ngx_core.h>#include <ngx_http.h>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_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_monitor_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_monitor_module.c"

这两个文件都放在ngx_http_monitor_module的文件夹下。


准备好这两个文件之后,我们定位到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

测试,我们可以得到如下结果




至此,自定义模块的编译与安装就结束了,是不是很简单?




原创粉丝点击