nginx中的ngx_http_request_t结构体详解

说明:一个request的完整周期是从client到server的请求加server到client的响应,请求和响应都存放在ngx_http_request_t结构体中,请求是存放在ngx_http_request_t中的request字段,此时response是空的。响应是放在ngx_http_request_t中的response中,此时为了保证效率和内存,nginx会将request释放。

转载地址:https://blog.csdn.net/yankai0219/article/details/8220621
0.序
在nginx中我们指的是 http请求,具体到nginx中的数据结构是 ngx_http_request_t。ngx_http_request_t是对一个http请求的封装。 我们知道,一个http请求,包含请求行、请求头、请求体、响应行、响应头、响应体。
nginx中http代表http请求的数据结构是ngx_http_request_t。
一个http请求,包含请求行、请求头、请求体、响应行、响应头、响应体。

http请求是典型的请求-响应类型的的网络协议,而http是文件协议,所以我们在分析请求行与请求头,以及输出响应行与响应头,往往是一行一行的进行处理。如果我们自己来写一个http服务器,通常在一个连接建立好后,客户端会发送请求过来。然后我们读取一行数据,分析出请求行中包含的method、uri、http_version信息。然后再一行一行处理请求头,并根据请求method与请求头的信息来决定是否有请求体以及请求体的长度,然后再去读取请求体。得到请求后,我们处理请求产生需要输出的数据,然后再生成响应行,响应头以及响应体。在将响应发送给客户端之后,一个完整的请求就处理完了。当然这是最简单的webserver的处理方式,其实nginx也是这样做的,只是有一些小小的区别,比如,当请求头读取完成后,就开始进行请求的处理了。nginx通过ngx_http_request_t来保存解析请求与输出响应相关的数据。


这短短的一段话蕴含的太多内容。
首先一个http请求包含请求消息与响应消息。请求消息包括请求行、请求头、请求体。响应消息包括响应行、响应头、响应体。
其次,在nginx中,ngx_http_request_t代表一个http请求,即ngx_http_request_t中包含了所有http请求的内容。
再次,关于message-body的存在与否,是与HTTP协议有关。
最后,得到请求后,我们处理请求产生需要输出的数据,再生成响应行、响应头、响应体。

另外,提到nginx的区别,当请求头读取完成后,就开始进行请求的处理。是因为nginx采用异步处理。在读取请求头后,就进行请求的处理,而对于message-body的处理则异步进行。、

一、ngx_http_request_t结构体解释


struct  ngx_http_request_s  {
     uint32_t                            signature ;          /* "HTTP" */
/*
与连接有关的内容
*/
     ngx_connection_t                  *  connection ;
/*
以下四个保存的是模块所对应的上下文结构体的指针。
其中ctx对应于自定义的上下文结构体指针
main_conf对应于main的上下文结构体指针
loc_conf对应于loc的上下文结构体指针
src_conf对应于srv的上下文结构体指针
*/

     void                             **  ctx ;
     void                             **  main_conf ;
     void                             **  srv_conf ;
     void                             **  loc_conf ;
 /*读写事件的函数指针*/
     ngx_http_event_handler_pt           read_event_handler ;
     ngx_http_event_handler_pt           write_event_handler ;

#if  (NGX_HTTP_CACHE)
     ngx_http_cache_t                  *  cache ;
#endif
/*
与upstream模块相关的结构体
*/
     ngx_http_upstream_t               *  upstream ;/*用于upstream模块*/
     ngx_array_t                       *  upstream_states ;/*与upstream模块相关*/
                                          /* of ngx_http_upstream_state_t */

     ngx_pool_t                        *  pool ;/*内存池*/
     ngx_buf_t                         *  header_in ; // 会保存一些消息体的内容

     ngx_http_headers_in_t               headers_in ;//代表请求头部  // 请求的header结构体
     ngx_http_headers_out_t              headers_out ;//代表响应头部

     ngx_http_request_body_t          * request_body;//代表请求头部 .r-> request_body-> bufs中存放的请求体中的数据


     time_t                              lingering_time ; /*unkown*/
     time_t                              start_sec ;/*unkown*/
     ngx_msec_t                          start_msec ; /*unkown*/

/*
从method到http_protocol都是请求行中信息
*/
     ngx_uint_t                          method ;
     ngx_uint_t                          http_version ;//http版本

     ngx_str_t                           request_line ;//请求行
     ngx_str_t                           uri
     ngx_str_t                           args ;
     ngx_str_t                           exten ;
     ngx_str_t                           unparsed_uri ;

     ngx_str_t                           method_name ;
     ngx_str_t                           http_protocol ;


     ngx_chain_t                       *  out ;   /*unkown*//*这里要注意ngx_http_request_t中有一个out的chain,这个chain保存的是上一次还没有被发完的buf,这样每次我们接收到新的chain的话,就需要将新的chain连接到老的out chain上,然后再发出去*/
/*接下来从main到posted_requests都是与主请求和子请求有关的内容/
     ngx_http_request_t                *  main ; //这个表示主的request,也就是当前的request链中最上面的那个request,通过这个域我们就能判断当前的request是不是subrequest。
     ngx_http_request_t                *  parent ; //这个表示当前的request的父request。
  //subrequest就是子请求,也就是在当前的一个请求中nginx再生成一个请求。
ngx_http_postponed_request_t      *  postponed ;// 先来看postponed,这个域用来缓存父request的数据(也就是将要发送数据的request)
     ngx_http_post_subrequest_t        *  post_subrequest ;// 这个域保存了子请求的post request,它也就是保存了需要被发送的request.
     ngx_http_posted_request_t         *  posted_requests ;// 这个保存了所有的需要处理的request链表,也就是说它即包含子请求也包含父请求
/* virtual hosts based on the address:port  
    r->virtual_names = addr_conf->virtual_names
*/  
     ngx_http_virtual_names_t          *  virtual_names ;

     ngx_int_t                           phase_handler ; /*应该是在请求处理的多个阶段中,利用phase_handler依次执行多个阶段*/
     ngx_http_handler_pt                 content_handler ; /*生成内容的处理函数 比如ngx_http_proxy_handler等*/
     ngx_uint_t                          access_code ;/*unkown*/

     ngx_http_variable_value_t         *  variables ;//variables 包含了所有的变量

#if  (NGX_PCRE)
     ngx_uint_t                          ncaptures ;
     int                               *  captures ;
     u_char                            *  captures_data ;
#endif

     size_t                              limit_rate ;/*unkown*/
/*
r->limit_rate,这个表示当前的request的发送限制速率,这个也是在nginx.conf中配置的,而一般就是通过这个值来设置c->write->delayed的。也就是说如果发送速率大于这个limit了的话,就设置delayed,然后这边的request就会延迟发送
*/

     /* used to learn the Apache compatible response length without a header */
     size_t                              header_size ;/*unkown*/

     off_t                               request_length ;/*unkown*/

     ngx_uint_t                          err_status ;/*unkown*/


     ngx_http_connection_t             *  http_connection ;/*unkown*/

     ngx_http_log_handler_pt             log_handler /*unkown*/

     ngx_http_cleanup_t                *  cleanup ;

     unsigned                            subrequests :8;
     unsigned                            count :8;
     unsigned                            blocked :8;

     unsigned                            aio :1;

     unsigned                            http_state :4;

     /* URI with "/." and on Win32 with "//" */
     unsigned                            complex_uri :1;

     /* URI with "%" */
     unsigned                            quoted_uri :1;

     /* URI with "+" */
     unsigned                            plus_in_uri :1;

     /* URI with " " */
     unsigned                            space_in_uri :1;

     unsigned                            invalid_header :1; // 一个标示位,标示header是否有效,不正常的结束视为无效

     unsigned                            add_uri_to_alias :1;
     unsigned                            valid_location :1;
     unsigned                            valid_unparsed_uri :1;
     unsigned                            uri_changed :1;
     unsigned                            uri_changes :4;
/ *
下面这两个参数就会设定为每个body都存放到临时文件里,并且这个临时文件在请求结束后不会被删除:

r->request_body_in_persistent_file = 1;

r->request_body_in_file_only = 1;

*/
     unsigned                            request_body_in_single_buf :1;
     unsigned                            request_body_in_file_only :1;
     unsigned                            request_body_in_persistent_file :1;
     unsigned                            request_body_in_clean_file :1;
     unsigned                            request_body_file_group_access :1;
     unsigned                            request_body_file_log_level :3;

     unsigned                            subrequest_in_memory :1;
     unsigned                            waited :1;

#if  (NGX_HTTP_CACHE)
     unsigned                            cached :1;
#endif

#if  (NGX_HTTP_GZIP)
     unsigned                            gzip_tested :1;
     unsigned                            gzip_ok :1;
     unsigned                            gzip_vary :1;
#endif

     unsigned                            proxy :1;
     unsigned                            bypass_cache :1;
     unsigned                            no_cache :1;

     /*
     * instead of using the request context data in
     * ngx_http_limit_conn_module and ngx_http_limit_req_module
     * we use the single bits in the request structure
     */
     unsigned                            limit_conn_set :1;
     unsigned                            limit_req_set :1;

#if  0
     unsigned                            cacheable:1;
#endif

     unsigned                            pipeline :1;
     unsigned                            plain_http :1;
     unsigned                            chunked :1;
     unsigned                            header_only :1;   /*当请求方法为HEAD时,r->header_only=1 ,在ngx_http_header_filter函数中*/
     unsigned                            keepalive :1;
     unsigned                            lingering_close :1;
     unsigned                            discard_body :1;
     unsigned                            internal :1;
     unsigned                            error_page :1;
     unsigned                            ignore_content_encoding :1;
     unsigned                            filter_finalize :1;
     unsigned                            post_action :1;
     unsigned                            request_complete :1;
     unsigned                            request_output :1;
     unsigned                            header_sent :1;
     unsigned                            expect_tested :1;
     unsigned                            root_tested :1;
     unsigned                            done :1;
     unsigned                            logged :1;

     unsigned                            buffered :4;

     unsigned                            main_filter_need_in_memory :1;
     unsigned                            filter_need_in_memory :1;
     unsigned                            filter_need_temporary :1;
     unsigned                            allow_ranges :1;

#if  (NGX_STAT_STUB)
     unsigned                            stat_reading :1;
     unsigned                            stat_writing :1;
#endif

     /* used to parse HTTP headers */
/*
通过打印,不能获得header_name_start内容
通过打印,可以获得header_start内容:为cookie内容+空行,也就是header_start内容包含cookie,但不仅仅包含cookie。
*/

     ngx_uint_t                          state ;

     ngx_uint_t                          header_hash ;
     ngx_uint_t                          lowcase_index ;
     u_char                              lowcase_header [NGX_HTTP_LC_HEADER_LEN];

     u_char                            *  header_name_start ;
     u_char                            *  header_name_end ;
     u_char                            *  header_start ;
     u_char                            *  header_end ;

     /*
     * a memory that can be reused after parsing a request line
     * via ngx_http_ephemeral_t
     */
/* used to parse HTTP 请求行的消息
** 通过打印,可以知道接下来这部分内容都是关于HTTP请求行的,通过这些指针可以方便找到所需的请求行中的内容,比如 r-> method_end+1,r-> http_protocol .data-1 之间就是URI。
*/

     u_char                            *  uri_start ;
     u_char                            *  uri_end ;
     u_char                            *  uri_ext ;
     u_char                            *  args_start ;
     u_char                            *  request_start ;
     u_char                            *  request_end ;
     u_char                            *  method_end ;
     u_char                            *  schema_start ;
     u_char                            *  schema_end ;
     u_char                            *  host_start ;
     u_char                            *  host_end ;
     u_char                            *  port_start ;
     u_char                            *  port_end ;

     unsigned                            http_minor :16;
     unsigned                            http_major :16;
};
测试中所添加函数内容:

#if  1
     printf (  "***ngx_http_upload_handler server :%s\t length is %d\n" ,out_headers_in. server .  data ,out_headers_in. server  . len );
    yk_print_ngx_str_t ( "server is "  ,r-> headers_in .  server . data  ,r-> headers_in .  server . len  );
    yk_print_ngx_str_t ( "request_line is "  ,r-> request_line .  data ,r-> request_line  . len );
    yk_print_ngx_str_t ( " uri is " ,r-> uri  . data ,r->  uri . len  );
    yk_print_ngx_str_t ( " args is " ,r-> args  . data ,r->  args . len  );
    yk_print_ngx_str_t ( "method_name is "  ,r-> method_name .  data ,r-> method_name  . len );
    yk_print_ngx_str_t ( "unparsed_uri is "  ,r-> unparsed_uri .  data ,r-> unparsed_uri  . len );

    yk_print_start2end(  "r->uri_start" ,r-> uri_start  ,r-> uri_end );
    yk_print_start2end(  "r->request_start" ,r-> request_start  ,r-> request_end );
    yk_print_start2end(  "r->schema_start" ,r-> schema_start  ,r-> schema_start );
    yk_print_start2end(  "r->host_start" ,r-> host_start  ,r-> host_start );
  //   printf("uri_ext is %s \t method_end is %s \t ",r->uri_ext,r->method_end);

    yk_print_start2end(  "uri is" ,r->  method_end +1,r-> http_protocol  . data -1);  /*这句话可以将 uri完整无错的打印出来*/
    yk_print_start2end(  "method_name start-end is"  ,r-> method_name .  data ,r-> method_end  +1); /*这句话可以将method完整无错的打印出来*/
     //yk_print_start2end("header_name_start is",r->header_name_start,r->header_name_end);
    yk_print_start2end(  "header_start is" ,r-> header_start  ,r-> header_end );
#endif


ngx_http_request_t 中header_in作用:
会保存一些消息体的内容,在用户名密码登陆的时候


     




二、ngx_http_request_body_t结构体
typedef  struct  {
     ngx_temp_file_t                   *  temp_file
     ngx_chain_t                       *  bufs ;/*消息体都保存在这个chain里面*/
     ngx_buf_t                         *  buf ;  /*用作临时存储的buf,在ngx_http_read_client_request_body和ngx_http_do_read_client_request_body中用得到 */
     off_t                               rest ;
     ngx_chain_t                       *  to_write ;
     ngx_http_client_body_handler_pt     post_handler ;
}  ngx_http_request_body_t ;
通过下面的语句可以打印bufs中内容。
/*below is edited by yankai*/
    yankai_cl = r->request_body->bufs;
    yankai_sum_rb_bufs = 0;
     for  (; yankai_cl; yankai_cl = yankai_cl->next){
          yankai_sum_rb_bufs += (size_t)ngx_buf_size(yankai_cl->buf);
    }
    printf(  "###yankai_sum_rb_bufs in ngx_http_upload_body_handler mm is %d\n" ,yankai_sum_rb_bufs);

ngx_http_headers_in_t结构体
下面这段话来自于http://tengine.taobao.org/book/chapter_12.html
ngx_http_headers_in_t结构的headers字段为一个链表结构,它被用来保存所有请求头,初始为它分配了20个节点,每个节点的类型为ngx_table_elt_t,保存请求头的name/value值对,还可以看到ngx_http_headers_in_t结构有很多类型为ngx_table_elt_t*的指针成员,而且从它们的命名可以看出是一些常见的请求头名字,nginx对这些常用的请求头在ngx_http_headers_in_t结构里面保存了一份引用,后续需要使用的话,可以直接通过这些成员得到,另外也事先为cookie头分配了2个元素的数组空间,做完这些内存准备工作之后,该请求对应的读事件结构的处理函数被设置为ngx_http_process_request_headers,并随后马上调用了该函数。
typedef  struct  {
     ngx_list_t                          headers ;
/*从host到keep_alive 均为常见的http头部字段*/
     ngx_table_elt_t                   *  host ;
     ngx_table_elt_t                   *  connection ;
     ngx_table_elt_t                   *  if_modified_since ;
     ngx_table_elt_t                   *  if_unmodified_since ;
     ngx_table_elt_t                   *  user_agent ;
     ngx_table_elt_t                   *  referer ;
     ngx_table_elt_t                   *  content_length ;
     ngx_table_elt_t                   *  content_type ;

     ngx_table_elt_t                   *  range ;
     ngx_table_elt_t                   *  if_range ;

     ngx_table_elt_t                   *  transfer_encoding ;
     ngx_table_elt_t                   *  expect ;

#if  (NGX_HTTP_GZIP)
     ngx_table_elt_t                   *  accept_encoding ;
     ngx_table_elt_t                   *  via ;
#endif

     ngx_table_elt_t                   *  authorization ;

     ngx_table_elt_t                   *  keep_alive ;

#if  (NGX_HTTP_X_FORWARDED_FOR)
     ngx_table_elt_t                   *  x_forwarded_for ;
#endif

#if  (NGX_HTTP_REALIP)
    ngx_table_elt_t                  *x_real_ip; 
#endif

#if  (NGX_HTTP_HEADERS)
    ngx_table_elt_t                  *accept;
    ngx_table_elt_t                  *accept_language;
#endif

#if  (NGX_HTTP_DAV)
    ngx_table_elt_t                  *depth;
    ngx_table_elt_t                  *destination;
    ngx_table_elt_t                  *overwrite;
    ngx_table_elt_t                  *date;
#endif

     ngx_str_t                           user ;/*unkown*/ 
     ngx_str_t                           passwd ;/*unkown*/ 

     ngx_array_t                         cookies ;

     ngx_str_t                           server ;


     off_t                               content_length_n ;/*unkown*/ 
     time_t                              keep_alive_n ;/*unkown*/ 

     unsigned                            connection_type :2;
     unsigned                            msie :1;
     unsigned                            msie6 :1;
     unsigned                            opera :1;
     unsigned                            gecko :1;
     unsigned                            chrome :1;
     unsigned                            safari :1;
     unsigned                            konqueror :1;
}  ngx_http_headers_in_t ;
说明:ngx_http_headers_in_t是包含请求头中所有内容,
             1)ngx_table_elt_t   都是RFC2616中提到的请求头域的内容
              2)user、passwd未知
              3)cookie里面保存的是cookie的内容,可以通过下面的代码打印出来
#if  0
     /*six line code source :http://lijinxing17.blog.163.com/blog/static/34977708201062710583500/*/
    ngx_table_elt_t ** cookies = NULL;
    ngx_uint_t i;
    printf(  "Cookie count: %d\n"  , r->headers_in.cookies.nelts);
    cookies = r->headers_in.cookies.elts;
     for  ( i = 0 ; i < r->headers_in.cookies.nelts; i++) {
                printf(  "Cookie line %d: %s\n"  , i, cookies[i]->value.data);
    }
#endif




四附录:里面用到的一些函数
/*
*函数功能:知道字符串的其实地址和中止地址,输出该字符串
*/
void  yk_print_start2end(  char  * description, u_char  * start, u_char  *end)
{
                  printf ( "%s\t"  ,description);
      u_char  * ptemp;
      for (ptemp = start; ptemp != end; ptemp++)
           printf ( "%c"  ,*ptemp);
      printf (  "\n" );
}
/*
*函数功能:知道字符串的其实地址和中止地址,输出该字符串
*/
void  yk_print_ngx_str_t(  char  * description, u_char  * data, int  len)
{
                  printf ( "%s\t"  ,description);
                  u_char  * ptemp;
                      for (ptemp = data; ptemp != (data + len); ptemp++)
                           printf ( "%c"  ,*ptemp);
                      printf ( "\n"  );
}


打印cookie内容
#if  0
     /*six line code source :http://lijinxing17.blog.163.com/blog/static/34977708201062710583500/*/
    ngx_table_elt_t ** cookies = NULL;
    ngx_uint_t i;
    printf(  "Cookie count: %d\n"  , r->headers_in.cookies.nelts);
    cookies = r->headers_in.cookies.elts;
     for  ( i = 0 ; i < r->headers_in.cookies.nelts; i++) {
                printf(  "Cookie line %d: %s\n"  , i, cookies[i]->value.data);
    }
#endif
五、一些没有搞清楚的成员变量
ngx_http_headers_in_t结构体中user passwd headers
ngx_connection_t *connection 
ngx_http_connection_t *http_connection
要在 Nginx 安装 ngx_http_mp4_module 模块,需要按照以下步骤进行操作: 1. 确认 Nginx 是否支持 ngx_http_mp4_module 模块 首先需要确认 Nginx 是否支持 ngx_http_mp4_module 模块,可以使用以下命令查看 Nginx 是否已经编译了该模块: ``` nginx -V 2>&1 | grep -o with-http_mp4_module ``` 如果输出结果为 with-http_mp4_module,则说明 Nginx 已经编译了 ngx_http_mp4_module 模块;如果输出结果为空,则说明 Nginx 没有编译该模块。 2. 下载 ngx_http_mp4_module 模块 如果 Nginx 没有编译 ngx_http_mp4_module 模块,需要下载该模块并添加到 Nginx 。可以从 Github 上下载该模块,链接为:https://github.com/kaltura/nginx-vod-module。 可以使用以下命令将 ngx_http_mp4_module 模块下载到 /opt 目录下: ``` cd /opt git clone https://github.com/kaltura/nginx-vod-module.git ``` 3. 编译 Nginx 并添加 ngx_http_mp4_module 模块 在编译 Nginx 时需要添加 --add-module=/opt/nginx-vod-module 参数来指定 ngx_http_mp4_module 模块所在的目录,具体命令如下: ``` ./configure --prefix=/usr/local/nginx --add-module=/opt/nginx-vod-module make make install ``` 4. 配置 NginxNginx 的配置文件添加以下内容,即可使用 ngx_http_mp4_module 模块: ``` location /video/ { mp4; mp4_buffer_size 1m; mp4_max_buffer_size 5m; } ``` 其,/video/ 是视频文件所在的目录。mp4 是 ngx_http_mp4_module 模块提供的指令,表示该目录下的文件都是 MP4 格式的视频文件。 mp4_buffer_size 和 mp4_max_buffer_size 是 ngx_http_mp4_module 模块提供的两个参数,用于控制视频文件的缓存大小。 5. 重启 Nginx 完成以上步骤后,需要重启 Nginx 使配置生效: ``` nginx -s reload ``` 至此,ngx_http_mp4_module 模块安装完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值