最近在研究如何利用 Nginx 实现高性能网关,这里记录一下开发 Nginx 扩展模块 Hello World。
编译安装 Nginx
下载 Nginx 源代码,解压,进入源代码目录:
wget http://nginx.org/download/nginx-1.13.10.tar.gz
tar zvxf nginx-1.13.10.tar.gz
cd nginx-1.13.10
编译,安装 Nginx 到指定目录:
./configure --prefix=/home/lihao/code/nginx/nginx-1.13.10/bin
make
make install
configure
命令中使用了参数 --prefix=/home/lihao/code/nginx/nginx-1.13.10/bin
是指将 Nginx 安装到目录 /home/lihao/code/nginx/nginx-1.13.10/bin
。
修改 /home/lihao/code/nginx/nginx-1.13.10/bin/conf/nginx.conf
,调整 Nginx 监听端口为 5123
:
server {
listen 5123;
server_name localhost;
启动 Nginx:
cd /home/lihao/code/nginx/nginx-1.13.10/bin
./sbin/nginx
打开浏览器,地址栏输入:http://服务器 ip:5123/
可以正常看到 Nginx 的欢迎页面。
开发 Nginx 模块
创建目录 ngx_http_hello_world_module
,然后在该目录创建两个文件 config
和 ngx_http_hello_world_module.c
。
config
文件
config
文件是个 shell 文件,用于告诉 Nginx 如何编译模块源代码。在 config
文件中,检测了当前 Nginx 版本是否支持动态模块,并采取不同的添加模块的方式。
ngx_addon_name=ngx_http_hello_world_module
if test -n "$ngx_module_link"; then
# The New Way
ngx_module_type=HTTP
ngx_module_name=ngx_http_hello_world_module
ngx_module_srcs="$ngx_addon_dir/ngx_http_hello_world_module.c"
. auto/module
else
# The Old Way
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
fi
C 模块文件
ngx_http_hello_world_module.c
用于实现自定义模块。
首先是函数 ngx_http_hello_world
的声明,这个函数会在源代码最后进行定义。
ngx_http_hello_world_commands
是个静态数组,用于定义 Nginx 指令。这里只定义一个指令 print_hello_world
,指令不需要参数,故定义为 NGX_CONF_NOARGS
。
ngx_http_hello_world_module_ctx
是个静态数组,用于定义函数,这些函数会在特定时刻执行,这里不需要,故都定义为 NULL
。
ngx_http_hello_world_module
是个静态数组,用于定义模块相关信息。
ngx_http_hello_world_handler
是模块的核心,实现在浏览器打印 Hello World!
。
最后是 ngx_http_hello_world
的定义,clcf->handler = ngx_http_hello_world_handler;
用于告诉 Nginx 自定义 handler ngx_http_hello_world_handler
。
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static char *ngx_http_hello_world(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_command_t ngx_http_hello_world_commands[] = {
{
ngx_string("print_hello_world"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_hello_world,
0,
0,
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,
ngx_http_hello_world_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
{
u_char *ngx_hello_world = (u_char *) "Hello World!";
size_t sz = strlen((const char *)ngx_hello_world);
r->headers_out.content_type.len = strlen("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = sz;
ngx_http_send_header(r);
ngx_buf_t *b;
ngx_chain_t *out;
b = ngx_calloc_buf(r->pool);
out = ngx_alloc_chain_link(r->pool);
out->buf = b;
out->next = NULL;
b->pos = ngx_hello_world;
b->last = ngx_hello_world + sz;
b->memory = 1;
b->last_buf = 1;
return ngx_http_output_filter(r, out);
}
static char *ngx_http_hello_world(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_hello_world_handler;
return NGX_CONF_OK;
}
编译模块源代码
在 Nginx 源代码目录,执行命令:
./configure --prefix=/home/lihao/code/nginx/nginx-1.13.10/bin --add-dynamic-module=/home/lihao/code/nginx/ngx_http_hello_world_module
make
make install
可以看到 Nginx 安装目录下 modules
目录,增加了 ngx_http_hello_world_module.so
文件。
使用模块
修改 Nginx 安装目录下的 nginx.conf
文件,在 server
下添加:
location /test {
print_hello_world;
}
打开浏览器,地址栏输入:http://服务器 ip:5123/test
,可以看到页面输出:Hello World!
。
参考资料
- https://tejgop.github.io/nginx-module-guide/
- https://zhuanlan.zhihu.com/p/50462530
- https://github.com/perusio/nginx-hello-world-module
- https://www.evanmiller.org/nginx-modules-guide.html
- https://github.com/openresty/lua-nginx-module
- https://blog.csdn.net/wangbufan/article/details/21169755