这是我参与更文挑战的第23天,活动详情查看: 更文挑战
背景
这是Nginx学习笔记汇总的第五篇,把定制开发Nginx插件的相关笔记汇总一下.
定制开发Nginx插件
Nginx开发常用模块
常见的三种需要定制开发的模块类型:handler,filter和load-balancer
Handler模块就是接受来自客户端的请求并产生输出的模块,upstream模块也可以称作是一种handler模块,只不过它产生的内容来自于从后端服务器获取的,而非在本机产生的
filter模块
内容产生阶段完成以后,生成的输出会被传递到filter模块去进行处理,filter模块也是与location相关的,所有的filter模块都被组织成一条链,输出会依次穿越所有的filter,直到有一个filter模块的返回值表明已经处理完成
几个常见的filter模块:
- server-side includes
- XSLT filtering
- 图像缩放之类的
- gzip 压缩
有几个filter模块比较特殊,按照调用的顺序依次说明如下:
- write: 写输出到客户端,实际上是写到连接对应的socket上
- postpone: 这个filter是负责subrequest的,也就是子请求的
- copy: 将一些需要复制的buf(文件或者内存)重新复制一份然后交给剩余的body filter处理
location和handler模块
配置文件中使用location指令可以配置content handler模块,当Nginx系统启动时,每个handler模块都有一次机会把自己关联到对应的location上,如果有多个handler模块都关联了同一个location,那么实际上只有一个handler模块真正会起作用,模块开发人员应避免出现这种情况
handler处理
handler模块处理的结果通常有三种情况:
- 处理成功
- 处理失败(处理的时候发生了错误)
- 拒绝去处理
在拒绝处理的情况下,这个location的处理就会由默认的handler模块来进行处理,例如,当请求一个静态文件的时候,如果关联到这个location上的一个handler模块拒绝处理,就会由默认的ngx_http_static_module模块进行处理,该模块是一个典型的handler模块
模块配置结构
- 每个模块都会提供一些配置指令,用户通过配置来控制该模块的行为,Nginx是通过定义该模块的配置结构来存储信息的
- Nginx的配置信息分成了几个作用域(scope,有时也称作上下文),这就是main,server以及location,每个模块提供的配置指令需要由三个不同的数据结构存储
- 模块的配置数据结构按需定义,需要在哪个作用域中使用就定义哪个,所以不是所有的模块都定义三个作用域的数据结构
- 在模块的开发过程中,最好使用Nginx原有的命名习惯,模块配置数据结构的命名习惯是ngx_http__(main|srv|loc)_conf_t
typedef struct {
ngx_str_t hello_string;
ngx_int_t hello_counter;
} ngx_http_hello_loc_conf_t;
ngx_command_t结构
ngx_command_t结构在src/core/ngx_conf_file.h中定义
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf;
ngx_uint_t offset;
void *post;
};
name: 配置指令的名称
type: 该配置的类型,或该配置指令属性的集合,Nginx提供了很多预定义的属性值(一些宏定义),通过逻辑或运算符可组合在一起,形成对这个配置指令的详细的说明,这些预定义属性值包括:
NGX_CONF_NOARGS:配置指令不接受任何参数
NGX_CONF_TAKE1:配置指令接受1个参数
NGX_CONF_TAKE2:配置指令接受2个参数
NGX_CONF_TAKE3:配置指令接受3个参数
NGX_CONF_TAKE4:配置指令接受4个参数
NGX_CONF_TAKE5:配置指令接受5个参数
NGX_CONF_TAKE6:配置指令接受6个参数
NGX_CONF_TAKE7:配置指令接受7个参数
可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数,那么就是NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2
Nginx提供了一些定义用于简化属性组合
NGX_CONF_TAKE12:配置指令接受1个或者2个参数
NGX_CONF_TAKE13:配置指令接受1个或者3个参数
NGX_CONF_TAKE23:配置指令接受2个或者3个参数
NGX_CONF_TAKE123:配置指令接受1个或者2个或者3参数
NGX_CONF_TAKE1234:配置指令接受1个或者2个或者3个或者4个参数
NGX_CONF_1MORE:配置指令接受至少一个参数
NGX_CONF_2MORE:配置指令接受至少两个参数
NGX_CONF_MULTI: 配置指令可以接受多个参数,即个数不定
NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块,也就是一对大括号括起来的内容,里面可以再包括很多的配置指令,比如常见的server指令就是这个属性的
NGX_CONF_FLAG:配置指令可以接受的值是"on"或者"off",最终会被转成 bool值
NGX_CONF_ANY:配置指令可以接受的任意的参数值,一个或者多个,或者"on"或者"off",或者是配置块
Nginx的配置指令的参数个数不可以超过NGX_CONF_MAX_ARGS个,这个值被定义为8,也就是不能超过8个参数值
配置指令可以出现的位置的属性:
NGX_DIRECT_CONF:可以出现在配置文件中最外层,例如已经提供的配置指令daemon,master_process等
NGX_MAIN_CONF: http、mail、events、error_log等
NGX_ANY_CONF: 该配置指令可以出现在任意配置级别上
大多数模块都是在处理http相关的事情,也就是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置:
NGX_HTTP_MAIN_CONF: 可以直接出现在http配置指令里
NGX_HTTP_SRV_CONF: 可以出现在http里面的server配置指令里
NGX_HTTP_LOC_CONF: 可以出现在http server块里面的location配置指令里
NGX_HTTP_UPS_CONF: 可以出现在http里面的upstream配置指令里
NGX_HTTP_SIF_CONF: 可以出现在http里面的server配置指令里的if语句所在的block中
NGX_HTTP_LMT_CONF: 可以出现在http里面的limit_except指令的block中
NGX_HTTP_LIF_CONF: 可以出现在http server块里面的location配置指令里的if语句所在的block中
为了更加方便的实现对配置指令参数的读取,Nginx默认提供了一些标准类型的参数的读取函数,可以直接赋值给set字段使用,下面是已实现的set类型函数:
ngx_conf_set_flag_slot: 读取NGX_CONF_FLAG类型的参数
ngx_conf_set_str_slot: 读取字符串类型的参数
ngx_conf_set_str_array_slot: 读取字符串数组类型的参数
ngx_conf_set_keyval_slot: 读取键值对类型的参数
ngx_conf_set_num_slot: 读取整数类型(有符号整数ngx_int_t)的参数
ngx_conf_set_size_slot: 读取size_t类型的参数,也就是无符号数
ngx_conf_set_off_slot: 读取off_t类型的参数
ngx_conf_set_msec_slot: 读取毫秒值类型的参数
ngx_conf_set_sec_slot: 读取秒值类型的参数
ngx_conf_set_bufs_slot: 读取的参数值是2个,一个是buf的个数,一个是buf的大小,例如output_buffers 1 128k;
ngx_conf_set_enum_slot: 读取枚举类型的参数,将其转换成整数ngx_uint_t类型
ngx_conf_set_bitmask_slot: 读取参数的值,并将这些参数的值以bit位的形式存储,例如HttpDavModule模块的dav_methods指令