Nginx开发HTTP模块入门
Nginx开发HTTP模块入门
我们以一个最简单的Hello World模块为例,学习Nginx的模块编写。假设我们的模块在nginx配置文件中的指令名称为hello_world
,那我们就可以在nginx.conf文件中配置这个指令
location / {
hello_world;
}
这样,当我们访问首页的时候就会执行hello_world
指令,输出Hello World。接下来,就开始编写我们的Hello World模块,按照nginx命名规则,我们把这个模块取名为ngx_http_hello_world_module
编写config文件
我们先建一个目录hello_world
来保存我们的扩展
mkdir /opt/nginx/ext/hello_world
要想一个办法把我们的模块编译到nginx中,我们需要在执行./configure
命令的时候加入--add-module=PATH
,这里的PATH就是我们扩展目录,所以我们要完成./configure
需要使用的config文件,在扩展目录下,新建config文件,
vim /opt/nginx/ext/hello_world/config
内容如下
ngx_addon_name=ngx_http_hello_world_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
CORE_LIBS="$CORE_LIBS -lpcre"
- ngx_addon_name:仅在configure执行时使用,一般设置为模块名称
- HTTP_MODULES:保存所有的HTTP模块名称,每个HTTP模块间由空格符相连,在重新设置HTTP_MODULES变量时,不要直接覆盖他,应该使用空格追加模块
- NGX_ADDON_SRCS:指定扩展模块的源代码
编写模块文件
编写好了config文件之后,就可以编写config文件中定义的模块文件了,新建模块文件
vim /opt/nginx/ext/hello_world/ngx_http_hello_world_module.c
定义HTTP模块
在nginx中,模块的数据类型是ngx_module_t
这个类型里面的成员详细可以参考源码,我们直接写出ngx_http_hello_world_module
模块定义
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx, /* module context */
ngx_http_hello_world_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
- NGX_MODULE_V1:表示版本号,使用内置的宏定义即可
- ngx_http_hello_world_module_ctx:这个成员很重要,设置上下文结构,HTTP框架要求,它必须指向
ngx_http_module_t
接口 - ngx_http_hello_world_commands:定义模块的配置文件参数,这个会作用在nginx.conf文件解析
- NGX_HTTP_MODULE:表示这是一个HTTP模块
编写模块上下文结构
这个结构体针对本文的HTTP模块来说,不需要调用,设置为NULL即可,但是HTTP框架要求,它必须指向ngx_http_module_t
接口,所以我们这样定义
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
编写命令结构
ngx_http_hello_world_commands
数组用于定义模块的配置文件参数,每一个元素都是ngx_command_t
类型,数组的结尾用ngx_null_command
表示。我们编写的模块的命令结构如下
static ngx_command_t ngx_http_hello_world_commands[] = {
{ ngx_string("hello_world"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_hello_world,
0,
0,
NULL },
ngx_null_command
}
- hello_world:表示我们的配置项名称,和gzip一样,设置名称而已
- NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS:指定出现的位置,可以出现在location{}块中
- ngx_http_hello_world:这是
ngx_command_t
中的set成员,当某块配置中出现hello_world
时候,nginx将会启动ngx_http_hello_world
方法,我们需要实现该函数
编写触发回调函数
前面编写完命令结构,定义了出现hello_world
配置项的时候触发ngx_http_hello_world
方法,我们要实现这个方法
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;
}
- ngx_http_conf_get_module_loc_conf:这个函数会首先找到
hello_world
配置项所属的配置块,然后赋值给变量clcf
- clcf->handler:HTTP框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果请求的主机域名,URL和
hello_wrold
相匹配,那么就调用这handler指向的方法ngx_http_hello_world_handler
编写对http请求的具体处理方法hander
前面分析,当匹配URL之后,真正执行的其实是我们的ngx_http_hello_world_handler
函数,所以,我们要实现这个函数
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
ngx_str_t type = ngx_string("text/plain");
ngx_str_t response = ngx_string("Hello World");
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);//向用户发送响应包
}
这个函数的参数是ngx_http_request_t
类型参数r,它包含了很多东西(方法,URI,协议,头部等)。
完整的例子
将上面的步骤联系起来,可以最终合并成我们的新模块文件ngx_http_hello_world_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);
static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_command_t ngx_http_mytest_commands[] = {
{
ngx_string("hello_world"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
ngx_http_hello_world,
NGX_HTTP_LOC_CONF_OFFSET,
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,
NGX_MODULE_V1_PADDING
};
static char *
ngx_http_mytest(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;
}
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
{
ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
ngx_str_t type = ngx_string("text/plain");
ngx_str_t response = ngx_string("Hello World");
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);
}
编译HTTP模块
经过上面的步骤,我们的扩展模块下面有两个文件在/opt/nginx/ext/hello_world
目录中
shell> ls /opt/nginx/ext/hello_world
config
ngx_http_hello_world_module.c
我们使用测试的nginx版本为nginx-1.0.10
。在安装过程中,执行./configure
的时候需要加入我们模块路径
shell> ./configure --add-module=/opt/nginx/ext/hello_world/nginx_hello_world/
然后进行安装即可
shell> make && make install
测试HTTP模块
修改nginx配置文件nginx.conf,如果不想配置规则,可以直接让访问首页的时候就执行hello_world执行
location / {
hello_world;
}
然后启动我们的nginx
shell> ./sbin/nginx
测试我们的nginx扩展的HTTP模块
shell> curl "127.0.0.1"
Hello World
Nginx开发HTTP模块入门的更多相关文章
- nginx开发_Filter模块执行顺序
Filter模块执行顺序 Filter模块的执行顺序是在执行configure文件时决定的,configure文件执行完成后生成objs/ngx_modules.c,文件中定义了一个数组ngx_mod ...
- Nginx开发从入门到精通 学习目录分享学习 (阿里著作)
Nginx开发从入门到精通 缘起 nginx由于出色的性能,在世界范围内受到了越来越多人的关注,在淘宝内部它更是被广泛的使用,众多的开发以及运维同学都迫切的想要了解nginx模块的开发以及它的内部 ...
- 转:Nginx国人开发缩略图模块(ngx_image_thumb)
ngx_image_thumb是nginx中用来生成缩略图的模块,生存缩略图的方法很多,之前也写过一篇 <nginx生成缩略图配置>,在github上发现国人开发的一款模块,作者的文档写的 ...
- nginx健康检查模块源码分析
nginx健康检查模块 本文所说的nginx健康检查模块是指nginx_upstream_check_module模块.nginx_upstream_check_module模块是Taobao定制的用 ...
- Nginx SPDY Pagespeed模块编译——加速网站载入
在看<Web性能权威指南>的时候,看到了SPDY这货,于是便开始折腾起了这个了,也顺便把pagespeed加了进去. Nginx SPDY 引自百科~~ SPDY(读作“SPeeDY”)是 ...
- 【转】前端Web开发MVC模式-入门示例
前端Web开发MVC模式-入门示例 MVC概论起初来之桌面应用开发.其实java的structs框架最能体现MVC框架:model模型是理解成服务器端的模块程序:view为发送给客服端的内容:cont ...
- nginx开发_ngx_palloc源码解析
功能简介 ngx_pool_t是nginx开发中最经常使用到的内存容器.对动态内存的封装,由框架进行创建与释放,模块开发过程中仅需要进行内存申请,不需要关注何时释放.常见的pool对象有: 1. ng ...
- nginx开发_配置项
nginx开发笔记_配置项 模块的配置项即nginx.conf中的指令,HTTP模块指令可以分为三个级别: main级,直接写在http{}块中的指令 server级,写在server{}块中的指令 ...
- Windows 编译安装 nginx 服务器 + rtmp 模块
有关博客: <Windows 编译安装 nginx 服务器 + rtmp 模块>.<Ubuntu 编译安装 nginx>.<Arm-Linux 移植 Nginx> ...
随机推荐
- 实战 TestNG 监听器
TestNG 是一个开源的自动化测试框架,其灵感来自 JUnit 和 NUnit,但它引入了一些新功能,使其功能更强大,更易于使用.TestNG 的设计目标是能够被用于进行各种类型测试:单元测试.功能 ...
- from表单
构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: 1 2 3 4 5 <form action="/your-name/" me ...
- 用css实现图片在div内的垂直居中
已知一个div内有一个img,两者的高度均不知道,但图片的高度一定小于div的高度 代码如下: .box { /*非IE的主流浏览器识别的垂直居中的方法*/ display: table-cell; ...
- C#编程技巧
拷贝/克隆(深度/浅拷贝).序列化.反射 Json/Xml 窗体的单例模式 https://www.cnblogs.com/imstrive/p/5426503.html 使用XmlSerialize ...
- 第五章 bean的加载(待续)
·············
- 第十二章 Java内存模型与线程(待续)
············
- DRF之解析器组件及序列化组件
知识点复习回顾一:三元运算 三元运算能够简化我们的代码, 请看如下代码: # 定义两个变量 a = 1 b = 2 # 判断a的真假值,如果为True,则将判断表达式的前面的值赋给c,否则将判断表达 ...
- Jquery获取EasyUI时间控件的值
jquery easyui日期控件中,在页面里用JS拿到设置的日期值的方法 jquery easyui 日期框 有这样的一个日期文本框: <input type=" value=&qu ...
- Wcf调用方式
C#动态调用WCF接口,两种方式任你选. 写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去 ...
- 【原】Coursera—Andrew Ng机器学习—Week 4 习题—Neural Networks 神经网络
[1] Answer:C [2] Answer:D 第二层要输出四个元素a1 a2 a3 a4.输入x有两个,加一个x0是三个.所以是4 * 3 [3] Answer:C [4] Answer:C [ ...