Nginx开发HTTP模块(四):定义自己的HTTP模块

决定自己的HTTP模块如何起作用

  • 一个HTTP请求会被许多个配置项控制,这是因为一个HTTP请求可以被许多个HTTP模块同时处理,所以肯定会有一个先后顺序的问题。
  • 我们面临的问题:
    • 我们希望自己的模块在哪个时刻开始处理请求?
    • 我们是希望自己的模块对到达Nginx的所有请求都起作用,还是只对某一类请求(如URI匹配了location后表达式的请求)起作用?
  • 定义第一个HTTP模块介入Nginx的方式
    • 模块并不对所有的HTTP请求起作用。
    • 在nginx.conf文件中的http{}、server{}或者location{}块内定义mytest配置项,如果一个用户请求通过主机域名、URI等匹配上了相应的配置块,而这个配置块下又具有mytest配置项,那么希望mytest模块开始处理请求。
    • 在这种介入方式下,模块处理请求的顺序是固定的,即必须在HTTP框架定义的NGX_HTTP_CONTENT_PHASE阶段开始处理请求。

开始定义mytest模块

  • 定义mytest配置项的处理
    • 只需要定义一个ngx_command_t数组,并将mytest配置项出现后的解析方法设置为ngx_http_mytest:
      static ngx_command_t ngx_http_mytest_commands[] = {
      {
          ngx_string("mytest"),
          NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
          ngx_http_mytest,
          NGX_HTTP_LOC_CONF_OFFSET,
          0,
          NULL
          },
          ngx_null_command
      };
      
      • ngx_http_mytest是ngx_command_t结构体中的set成员,当在某个配置块中出现mytest配置项时,Nginx将会调用ngx_http_mytest方法。
  • 实现ngx_http_mytest方法
    static char * ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
        ngx_http_core_loc_conf_t *clcf;
    
        /* 首先找到mytest配置项所属的配置块,clcf看上去像是location块内的数据结构,其实不然,
         * 它可以是main、src或者loc级别的配置项,也就是说,在每个http{}和server{}内也都有一个
         * ngx_http_core_loc_conf结构体
         */
        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    
        /* HTTP框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段是,如果请求的主机域名、URL
         * 与mytest配置项所在的配置块相匹配,就将调用我们实现的ngx_http_mytest_handler方法处
         * 理这个请求
         * */
        clcf->handler = ngx_http_mytest_handler;
    
        return NGX_CONF_OK;
    }
    
    • 当Nginx接收完HTTP请求的头部信息时,就会调用HTTP框架处理请求,NGX_HTTP_CONTENT_PHASE阶段将有可能调用mytest模块处理请求。
    • 在ngx_http_mytest方法中,定义了请求的处理方法为ngx_http_mytest_handler。
    • HTTP框架共定义了11个阶段,第三方模块只能介入其中的7个阶段处理请求。11个阶段的定义如下:
      typedef enum {
      	// 在接收到完整的HTTP头部后处理的HTTP阶段
          NGX_HTTP_POST_READ_PHASE = 0,
      
      	/* 在还没有查询到URI匹配的location前,这时rewrite重写URL也作为一个独立的HTTP阶段 */
          NGX_HTTP_SERVER_REWRITE_PHASE,
      
      	/* 
      	根据URI寻找匹配的location,这个阶段通常由ngx_http_core_module模块实现。
      	不建议其他HTTP模块重新定义这一阶段的行为。 
      	*/
          NGX_HTTP_FIND_CONFIG_PHASE,
          /*
      	NGX_HTTP_FIND_CONFIG_PHASE阶段后重写URL的意义与NGX_HTTP_SERVER_REWRITE_PHASE阶段不同
      	因为这两者会导致查找到不同的location块(location是与URI进行匹配的)
      	*/
          NGX_HTTP_REWRITE_PHASE,
          /*
      	该阶段用于在rewrite重写URL后跳到NGX_HTTP_FIND_CONFIG_PHASE,找到与新的URI匹配的location。
      	这一阶段无法由第三方HTTP模块处理,仅由ngx_http_core_module模块使用
      	*/
          NGX_HTTP_POST_REWRITE_PHASE,
      	// 处理NGX_HTTP_ACCESS_PHASE阶段前,HTTP模块可以介入的处理阶段
          NGX_HTTP_PREACCESS_PHASE,
      	// 这个阶段用于HTTP模块判断是否允许这个请求访问Nginx服务器
          NGX_HTTP_ACCESS_PHASE,
          /*
          当NGX_HTTP_ACCESS_PHASE阶段中HTTP模块的handler处理方法返回不允许访问的错误码时
          (实际是NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUTHORIZED),这个阶段负责构造拒绝服务的用户响应。
          这个阶段实际上用于给NGX_HTTP_ACCESS_PHASE阶段收尾。
          */
          NGX_HTTP_POST_ACCESS_PHASE,
      	/*
      	这个阶段完全是为try_files配置项而设立的。
      	当HTTP请求访问静态文件资源时,try_files配置项可以使这个请求顺序地访问多个静态文件资源。
      	如果某一次访问失败,则继续访问try_files中指定的下一个静态资源。
      	这个功能完全是在NGX_HTTP_TRY_FILES_PHASE阶段中实现的。
      	*/
          NGX_HTTP_PRECONTENT_PHASE,
      	// 用于处理HTTP请求内容的阶段,这是大部分HTTP模块最喜欢介入的阶段
          NGX_HTTP_CONTENT_PHASE,
      	/*
      	处理完请求后记录日志的阶段。
      	ngx_http_log_module模块就在这个阶段中加入了一个handler处理方法,
      	使得每个HTTP请求处理完毕后会记录access_log日志
      	*/
          NGX_HTTP_LOG_PHASE
      } ngx_http_phases;
      
  • 定义ngx_http_module_t接口
    • 如果没有什么工作是必须在HTTP框架初始化时完成的,那就不必实现ngx_http_module_t的8个回调方法,定义方法如下:
      static ngx_http_module_t ngx_http_mytest_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 */
      };
      
  • 定义mytest模块
    ngx_module_t ngx_http_mytest_module = {
        NGX_MODULE_V1,
        &ngx_http_mytest_module_ctx,    /* module context */
        ngx_http_mytest_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
    };
    

至此,mytest模块在编译时将会被加入到ngx_modules全局数组中。Nginx在启动时,会调用所有模块的初始化回调方法,当然,这个例子中我们没有实现它们(也没有实现HTTP框架初始化时会调用的ngx_http_module_t中的8个方法)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值