Nginx学习笔记系列第五篇-开发Nginx插件

527 阅读6分钟

这是我参与更文挑战的第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指令