开发一个简单的http模块
如何调用http模块
准备工作
ngx_http_mytest_module
ngx_http_mytest_module.c需要定义一个名称,以便在configure时显示是否执行成功。
整型的封装
ngx_int_t封装有符号整型,使用ngx_uint_t 封装无符号整型。
ngx_str_t数据结构
typedef struct{
size_t len;
u_char *data;
}ngx_str_t;
ngx_list_t数据结构
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s{
void *elts; //指向数组的起始地址
ngx_uint_t nelts; //表示数组中已经使用了多少个元素
ngx_list_part_t *next; //下一个链表元素的地址
}
typedef struct{
ngx_list_part_t *last; //指向链表的最后一个数组元素
ngx_list_part_t part; //链表的首个数组元素
size_t size;//限制用户要存储的一个数据所占用的字节数必须小于或等于size
ngx_uint_t nalloc; //每个ngx_list_part_t数组的容量
ngx_pool_t *pool; //管理内存分配的内存池对象
}ngx_list_t; //整个链表
ngx_table_elt_t数据结构
typedef struct{
ngx_uint_t hash;
ngx_str_t key;
ngx_str_t value;
u_char *lowcase_key;
}ngx_table_elt_t;
ngx_buf_t数据结构
本质上是一些指针成员和标志位
ngx_chain_t数据结构
ngx_chain_t是与ngx_buf_t配合使用的链表数据结构
typedef struct ngx_chain_s ngx_chain_t;
struct ngx_chain_s{
ngx_buf_t *buf;
ngx_chain_t *next;
}
将自己的http模块编译进nginx
源代码全部放到一个目录下,同时编写一个文件用于通知nginx如何编译本模块,这个文件名必须为config。
在configure脚本执行时加入参数 –add-module=PATH
不满足要求时,直接修改objs/Makefile 和 objs/ngx_modules.c文件
config文件的写法
只想开发一个http模块,需要定义一下3个变量
ngx_addon_names:仅在configure时使用,一般为模块名称
HTTP_MODLUES:保存所有的HTTP模块名称,每个模块有空格符相连
"$HTTP_MODLUES ngx_http_mytest_module"
NGX_ADDON_SRCS:新模块的源代码
可以使用$ngx_addon_dir 等价于configure时的--addon-module=PATH
利用configure脚本将定制的模块加入到nginx中
configure中的两行脚本负责将第三方模块加入到nginx
. auto/modules
. auto/make
直接修改Makefile文件
在执行完configure后,对生成的objs/ngx_modules.c和objs/Makefile文件直接进行修改。
http模块的数据结构
定义http模块:
ngx_module_t ngx_http_mytest_module;
ngx_uint_t ctx_index; //表示在一类模块中的序号
ngx_uint_t index; //表示在ngx_modules数组中的序号
void *ctx;指向特定类型模块的公共接口
ngx_command_t *commands; //commands将处理nginx.conf中的配置项
ngx_uint_t type;//该模块的类型,在nginx官方中,取值为以下NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_MAIL_MODULE
定义自己的http模块
此处的示例:
- 不希望模块对所有的http请求起作用
- 在nginx文件中的http{}、server{}、location{}块内定义mytest配置项,如果一个用户请求通过主机域名、URI等匹配上了相应的配置块,配置块下又有相应的mytest配置项,那么希望mytest模块开始处理请求
- 首先,定义mytest配置项的处理 (常用NGX_HTTP_CONTENT_PHASE)
- 定义模块
处理用户请求
在出现mytest配置项时,ngx_http_mytest方法或被调用,这时将ngx_http_core_loc_conf_t结构的handler成员指定我ngx_http_mytest_handler,在接收完http请求头部后,会调用handler指向的方法
handler 成员的原型ngx_http_mytest_handler_handler_pt
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
处理方法的返回值
http中相应包的返回码,包括了在/src/http/ngx_http_request.h文件中定义好的宏。
获取URI和参数
可以在ngx_http_request_t类型参数的r 中取得
获取http头部
struct ngx_http_request_s{
...
ngx_buf_t *header_in; //未解析
ngx_http_headers_in_t headers_in;//解析
...
}
获取http包体
http框架提供一种方法异步地接收包体
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,ngx_http_client_body_handler_pt post_handler);
发送响应
发送http头部
ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
将内存中的字符串作为包体发送
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r,ngx_chain_t *in);
“Hello World”示例
将磁盘文件作为包体发送
如何发送磁盘文件
发送文件与内存数据的不同在于 如何设置ngx_buf_t
in_file为1表示缓冲区发送的是文件
清理文件句柄
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
用户多线程下载和断点续传
range协议
用c++编写http模块
编译方式的修改
- 修改configure相关脚本
- 修改configure执行完毕后生成的Makefile文件(推荐)