参考资料:深入理解Nginx(陶辉)

书中有详细的讲解,这里只用本人的理解梳理一下该流程。

一点提议:对于像我这样的新手,面对暂时看不懂章节,建议先往下看一下(可能就会有新的理解或灵感),而不要死磕在某一章节。

几个重要的数据结构

定义一个用于测试的结构体

我们的测试模块将使用该结构体来存放配置信息,该结构只存放一个ngx_str_t。

typedef struct {
  ngx_str_t my_str;
} ngx_http_mytest_conf_t;

先看看ngx_http_module_t的定义

typedef struct {
  ngx_int_t (*preconfiguration)(ngx_conf_t *cf); //解析配置文件前调用
  ngx_int_t (*postconfiguration)(ngx_conf_t *cf); //完成配置文件解析后调用
  void *(*create_main_conf)(ngx_conf_t *cf); //当需要创建数据结构用户存储main级别的全局配置项时候调用
  char *(*init_main_conf)(ngx_conf_t *cf, void *conf); //初始化main级别配置项
  void *(*create_srv_conf)(ngx_conf_t *cf); //当需要创建数据结构用户存储srv级别的全局配置项时候调用
  char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); //合并server级别的配置项
  void *(*create_loc_conf)(ngx_conf_t *cf); //当需要创建数据结构用户存储loc级别的全局配置项时候调用
  char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); //合并location级别的配置项
} ngx_http_module_t;

HTTP框架定义了3个级别的配置main、srv、loc,分别表示直接出现在http{}、server{}、location{}块内的配置项。
例如:当解析遇到http{}配置块时,会调用create_main_conf回调函数来创建并返回每个HTTP模块对应的结构体(对于我们的测试模块是ngx_http_mytest_conf_t)。

我们的mytest模块实现create_loc_conf的是ngx_http_mytest_create_loc_conf方法

static void *ngx_http_mytest_create_loc_conf(ngx_conf_t *cf)
{
  //创建mytest模块对应的结构体ngx_http_mytest_conf;
  ngx_http_mytest_conf_t *mycf;
  mycf=(ngx_http_mytest_conf_t *)ngx_pcalloc(cf->pool,sizeof(ngx_http_mytest_conf_t));
  if(mycf==NULL){
    return NULL;
  }
  return mycf;
}

那么Nginx是怎么保存这些配置信息的呢?

再看看ngx_http_conf_ctx_t结构

typedef struct {
  /* 指针数组,数组中的每个元素指向所有HTTP模块create_main_conf方法产生的结构体*/
  void **main_conf;
  /* 指针数组,数组中的每个元素指向所有HTTP模块create_srv_conf方法产生的结构体*/
  oid **srv_conf;
  /* 指针数组,数组中的每个元素指向所有HTTP模块create_loc_conf方法产生的结构体*/
  void **loc_conf;
} ngx_http_conf_ctx_t;

用于定义模块的配置参数的结构体ngx_command_t

typedef struct ngx_command_s ngx_command_t;
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:配置项的参数类型、参数个数以及配置项可以在哪些位置出现(http、server、location等)
set:处理配置项的回调方法。Nginx提供了14个预设的解析配置项的方法。
conf:对于HTTP模块,conf是必须设置的,它的取值范围见下表

offset:当前配置项在整个存储配置项的结构体中的偏移位置。对于使用Nginx预设的解析方法:
         Nginx首先通过conf成员找到应该用哪个结构体来存放,然后通过offset成员找到这个结构体中的相应成员,以便存放该配置。

在mytest模块中,我们将这样定义一个ngx_command_t数组

static ngx_command_t ngx_http_mytest_commands[] = {
  {
    ngx_string("test_str"), //配置项名称
    NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, //配置项只能出现在location块中并且配置参数数量为1个
    ngx_conf_set_str_slot, //使用预设的解析方法解析配置参数,表示我们希望用ngx_str_t类型的变量来保存这个配置项的参数
    NGX_HTTP_LOC_CONF_OFFSET, //使用create_loc_conf方法产生的结构体来存储解析出的配置项参数
    offsetof(ngx_http_mytest_conf_t,my_str); //与上面两个成员一起使用,通过这3个成员来找到该配置参数存放的位置(ngx_http_mytest_conf_t.my_str)。
    NULL
  },
  ngx_null_command
};

HTTP配置的流程

1.主循环调用配置文件解析器解析nginx.conf文件。

2.当发现配置文件中含有http{}关键字时,HTTP框架开始启动。

3.初始化所有HTTP模块的序列号,并创建ngx_http_conf_ctx_t结构。

4.调用每个HTTP模块的create_main_conf、create_srv_conf、create_loc_conf方法。

5.把各HTTP模块上述3个方法返回的地址依次保存到ngx_http_conf_ctx_t结构体的3个数组中(如果某个模块没有定义相应的方法,则为NULL)。

6.调用每个HTTP模块的preconfiguration方法。

7.如果preconfiguration返回失败,那么Nginx进程将会停止。

8.HTTP框架开始循环解析nginx.conf文件中http{...}里面的所有配置项

9.配置文件解析器在检测到一个配置项后,会遍历所有HTTP模块,检查它们的ngx_command_t数组中的name项是否与配置项名相同。

10.如果找到一个HTTP模块对这个配置项感兴趣,就调用ngx_command_t结构中的set方法来处理该配置项。

11.如果set方法返回失败,那么Nginx进程会停止。

12.配置文件解析器继续检查配置项。如果发现server{...}配置项,就会调用ngx_http_core_module模块来处理。

13.ngx_http_core_module模块在解析server{...}之前,也会如第三步一样建立ngx_http_conf_ctx_t结构,并调用每个HTTP模块的create_srv_conf、create_loc_conf回调方法。

14.将上一步各HTTP模块返回的指针地址保存到ngx_http_conf_ctx_t对应的数组中。

15.开始调用配置文件解析器来处理server{...}里面的配置项。

16.继续重复第9步的过程,遍历nginx.conf中当前server{...}内的所有配置项。

17.配置文件解析器继续解析配置项,如果发现当前server块已经遍历到尾部,则返回ngx_http_core_module模块。

18.返回配置文件解析器继续解析后面的配置项。

19.配置文件解析器继续解析配置项,如果发现处理到了http{...}的尾部,返回个HTTP框架继续处理。

20.调用merge_srv_conf、merge_loc_conf等方法合并这些不同块中每个HTTP模块分配的数据结构。

21.HTTP框架处理完毕http配置项,返回给配置文件解析器继续处理其他http{...}外的配置项。

22.配置文件解析器处理完所有配置项后告诉Nginx主循环配置项解析完毕,这是Nginx才会启动Web服务器。

注意:上面还有一些我们没有列出来的步骤(如发现其他server块或者location块)。它们都会创建ngx_http_conf_ctx_t结构。

HTTP配置模型的内存布局

mytest模块的完整代码

 #include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h> typedef struct{
ngx_str_t my_str;
}ngx_http_mytest_conf_t; static ngx_int_t
ngx_http_mytest_handler(ngx_http_request_t *r); //创建mytest模块对应的结构体ngx_http_mytest_conf;
static void *ngx_http_mytest_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_mytest_conf_t *mycf;
mycf=(ngx_http_mytest_conf_t *)ngx_pcalloc(cf->pool,sizeof(ngx_http_mytest_conf_t));
if(mycf==NULL){
return NULL;
}
return mycf;
} static ngx_command_t ngx_http_mytest_commands[] = {
{
ngx_string("response_line"), //配置项名称
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, //配置项只能出现在location块中并且配置参数数量为1个
ngx_conf_set_str_slot, //使用预设的解析方法解析配置参数,表示我们希望用ngx_str_t类型的变量来保存这个配置项的参数
NGX_HTTP_LOC_CONF_OFFSET, //使用create_loc_conf方法产生的结构体来存储解析出的配置项参数
offsetof(ngx_http_mytest_conf_t,my_str), //与上面两个成员一起使用,通过这3个成员来找到该配置参数存放的位置(ngx_http_mytest_conf_t.my_str)。
NULL
},
ngx_null_command
}; //挂载handler
static ngx_int_t
ngx_http_mytest_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
} *h = ngx_http_mytest_handler; return NGX_OK;
} static ngx_http_module_t ngx_http_mytest_module_ctx={
NULL,
ngx_http_mytest_init,
NULL,
NULL,
NULL,
NULL,
ngx_http_mytest_create_loc_conf,
NULL
}; ngx_module_t ngx_http_mytest_module={
NGX_MODULE_V1,
//指向ngx_http_module_t结构体
&ngx_http_mytest_module_ctx,
//用来处理nginx.conf中的配置项
ngx_http_mytest_commands,
//表示该模块的类型
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
}; static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
//判断请求方法是否为GET或者HEAD,否则返回405 Not Allowed
if(!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))){
return NGX_HTTP_NOT_ALLOWED;
} //丢弃请求中的包体
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_http_mytest_conf_t* my_conf;
my_conf = ngx_http_get_module_loc_conf(r, ngx_http_mytest_module);
ngx_str_t response=my_conf->my_str;
r->headers_out.status=NGX_HTTP_OK;
r->headers_out.content_length_n=response.len;
r->headers_out.content_type=type; //发送HTTP头部
rc=ngx_http_send_header(r);
if(rc==NGX_ERROR||rc>NGX_OK||r->header_only){
return rc;
} //构造ngx_buf_t结构体准备发送包体
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=; //构造发送时的ngx_chain_t结构体
ngx_chain_t out;
out.buf=b;
out.next=NULL;
return ngx_http_output_filter(r,&out);
}

按照http://www.cnblogs.com/runnyu/p/4871866.html编译安装该模块

在nginx.conf文件中默认server块下配置如下信息

location /response {
response_line HelloWorld\r\n;
}

使用telnet查看结果

Nginx:解析HTTP配置的流程的更多相关文章

  1. nginx解析漏洞,配置不当,目录遍历漏洞环境搭建、漏洞复现

    nginx解析漏洞,配置不当,目录遍历漏洞复现 1.Ubuntu14.04安装nginx-php5-fpm 安装了nginx,需要安装以下依赖 sudo apt-get install libpcre ...

  2. windows下搭建nginx服务器及实现nginx支持https配置流程

    最近刚接触到了tomcat结合nginx做网站的负载均衡.之前对tomcat搭配nginx实现负载均衡也写过,在上一篇的博客中,最近遇到的问题是要在http的基础上支持https.也就是支持加密的请求 ...

  3. BeanDefinition 解析流程【解析所有配置类】

    BeanDefinition 解析流程 BeanDefinition 解析入口:ConfigurationClassPostProcessor#postProcessBeanDefinitionReg ...

  4. Ubuntu14.04(nginx+php+mysql+vsftp)配置安装流程

    Ubuntu14.04(nginx+php+mysql+vsftp)配置安装流程 1.先切换到root用户 sudo  su 2.更新软件源 apt update apt-get upgrade 3. ...

  5. Linux centos VMware Nginx防盗链、Nginx访问控制、Nginx解析php相关配置、Nginx代理

    一.Nginx防盗链 配置如下,可以和上面的配置结合起来 location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|x ...

  6. Nginx(六):配置解析之location解析

    nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能.但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性. 那么,今天我们 ...

  7. Nginx 解析PHP的原理 | CGI、FastCGI及php-fpm的关系

    Nginx解析PHP的原理,CGI/FastCGI以及PHP-Fpm的关系. 一.PHP+Nginx应运而生的场景.随着互联网的发展,用户对此接受面广,数据流的增大使得Web端的运行承载压力日益增大, ...

  8. 如何配置nginx负载均衡配置(轮询,权重,ip绑定)

    集群是为了解决单节点无法服务高并发的情况,在集群中nginx是如何分配将来自客户端的请求 转发给服务器的 负载均衡可以提高网站的吞吐量(接受和响应),减轻单台服务器的压力 负载均衡提供了三种策略:轮询 ...

  9. Nginx解析PHP的原理 | CGI、FastCGI及php-fpm的关系

    Nginx解析PHP的原理,CGI/FastCGI以及PHP-Fpm的关系. 一.PHP+Nginx应运而生的场景.随着互联网的发展,用户对此接受面广,数据流的增大使得Web端的运行承载压力日益增大, ...

随机推荐

  1. linux缺页异常处理--内核空间【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7867720 版权声明:本文为博主原创文章,未经博主允许不得转载. 缺页异常被触发通常有两种情况 ...

  2. vue.js基本使用

    #原创,转载请留言联系 什么是vue.js Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架. Vue 只关注视图层, 采用自底向上增量开发的设计. Vue 的目 ...

  3. AC日记——Paint Pearls hdu 5009

    Paint Pearls 思路: 离散化+dp+剪枝: dp是个n方的做法: 重要就在剪枝: 如果一个长度为n的区间,有大于根号n种颜色,还不如一个一个涂: 来,上代码: #include <c ...

  4. HDU 6300.Triangle Partition-三角形-水题 (2018 Multi-University Training Contest 1 1003)

    6300.Triangle Partition 这个题就是输出组成三角形的点的下标. 因为任意三点不共线,所以任意三点就可以组成三角形,直接排个序然后输出就可以了. 讲道理,没看懂官方题解说的啥... ...

  5. (1) C语言 基础1

     VS  scanf 安全错误 在预处理器定义那里添加一行_CRT_SECURE_NO_DEPRECATE vs编译头错误 一.打印helloworld #include<stdio.h> ...

  6. 洛谷 P1060 开心的金明【DP/01背包】

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就 ...

  7. “玲珑杯”ACM比赛 Round #1

    Start Time:2016-08-20 13:00:00 End Time:2016-08-20 18:00:00 Refresh Time:2017-11-12 19:51:52 Public ...

  8. 【高精度】高精度数除以低精度数I

    问题 G: [高精度]高精度数除以低精度数I 时间限制: 1 Sec  内存限制: 512 MB提交: 173  解决: 71[提交] [状态] [讨论版] [命题人:] 题目描述 修罗王聚集了庞大的 ...

  9. Quaternion Euler

    geometry_msgs::Quaternion orientation = map->info.origin.orientation;      tf::Matrix3x3 mat(tf:: ...

  10. luogu P1284 三角形牧场

    题目描述 和所有人一样,奶牛喜欢变化.它们正在设想新造型的牧场.奶牛建筑师Hei想建造围有漂亮白色栅栏的三角形牧场.她拥有N(3≤N≤40)块木板,每块的长度Li(1≤Li≤40)都是整数,她想用所有 ...