请在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

本文主要参考为《深入理解nginx模块开发与架构解析》一书,处理用户请求部分,是一篇包含作者理解的读书笔记。欢迎指正,讨论。

handler函数的定义模型如下:

 static ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)
{}

请求的所有信息都可以在传入的ngx_http_request_t类型指针参数 r 中获得。Ngx_http_request_t结构体包含的内容很多,这里只讨论其中获取HTTP请求的部分,相关定义如下:

  struct ngx_http_request_s {
...
  //请求头
ngx_buf_t *header_in; ngx_http_headers_in_t headers_in;
ngx_http_headers_out_t headers_out;
  //请求体
ngx_http_request_body_t *request_body;
  //请求行
ngx_uint_t method;
ngx_uint_t http_version; 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;
...
/*
24 * a memory that can be reused after parsing a request line
25 * via ngx_http_ephemeral_t
26 */ 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;
...
};

相关定义全在上面列出,

下面,我们先从请求行的获取来解释:

http请求行定义如下:

<method><request-URL><version>

首先,需要解析method:

  • method的定义类型为ngx_uint_t,Nginx中通过宏定义,给所有method赋予了不同的整型值。这里的method是Nginx解析了用户请求之后得到的整型值,可以用来判断method。
  • method_name则是ngx_str_t类型,内容是方法名字符串,其使用方式区别于常用str类型,这点一定要注意。
  • 还可以使用request_start和method_end指针取得方法名,request_start指向用户请求的首地址,同时也是方法名的地址,method_end则指向方法名的最后一个字符(注意:这点与其他xxx_end指针不同)。

然后,解析URI:

  • ngx_str_t类型的uri指向用户请求的URI。
  • uchar*类型的uri_start和uri_end也和method的用法类似。不同的是,method_end指向的是方法名的最后一个字符,而uri_end指向URI结束之后的下一个字符。也就是最后一个字符的下一个字符地址。Nginx中大部分的u_char*类型指针变量中的“xxx_start”和“xxx_end”都是这样使用的。

  • ngx_str_t类型的extern类型指向用户请求的文件的扩展名。例如:在访问“GET /a.txt HTTP/1.1”时,extern的值为{len=3,data=“txt”}。

  • uri_ext指针指向的地质与extern.data相同unparsed_uri表示没有进行uri解码的原始请求。例如:“/a b”的原始请求为“/a%20b”(空格字符的编码为%20)。

接着,解析URI参数:

  • Arg指向用户请求中的URL参数。

  • Args_start和配合uri_end使用可以获得URL的参数。

最后,协议版本的获取:

  • http_protocol指向用户请求中的HTTP的起始地址。

  • http_version是nginx解析过得协议版本,他的取值范围如下:

  

#define NGX_HTTP_VERSION_9                 9
#define NGX_HTTP_VERSION_10 1000
#define NGX_HTTP_VERSION_11 1001
  • 建议使用http_version分析HTTP协议的版本。

  • 最后使用request_start 和 request_end可以获取原始的用户请求。

请求行的获取到此结束,下面是请求头的获取:

head_in指向nginx收到的未经解析的HTTP头部。这里先不关注。

ngx_http_request_t中ngx_http_headers_in_t类型的headers_in则储存已经解析过得HTTP头部。结构体定义如下:

 typedef struct {
ngx_list_t headers; 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 *if_match;
ngx_table_elt_t *if_none_match;
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;
ngx_table_elt_t *upgrade; #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_array_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;
ngx_str_t passwd; ngx_array_t cookies; ngx_str_t server;
off_t content_length_n;
time_t keep_alive_n; unsigned connection_type:;
unsigned chunked:;
unsigned msie:;
unsigned msie6:;
unsigned opera:;
unsigned gecko:;
unsigned chrome:;
unsigned safari:;
unsigned konqueror:;
} ngx_http_headers_in_t;

结构体中,后面定义了很多ngx_table_elt_t类型的指针变量,ngx_table_elt_t类型是Nginx定义的字典类型。内容都指向Nginx已经解析过得标准常见的HTTP头部,可以直接使用。这些解析过了的头部其实都储存在headers链表中,所以,对于headers_in结构体中未定义的不常用的HTTP头部,就需要遍历headers链表,解析其值。

下面是一个解析的例子(源于《深入理解》一书):

下面尝试在一个用户请求中找到“Rpc-Description”头部,首先判断其值是否为“uploadFile”,再决定后续的服务器行为。

ngx_list_part_t *part = &r->headers_in.headers.part;
ngx_table_elt_t *header = part->elts; //开始遍历链表
for(i = ;/*void*/;i++){
//判断是否到达链表中当前数组结尾
if(i>=part->nelts){
//是否还有下一个链表数组元素
if(part->next == NULL){
break;
}
//part设置为next来访问下一个链表数组;header也指向下一个链表数组的首地址,设置i为0,表示从头开始遍历新的链表数组。
part = part->next;
header = part->elts;
i=;
}
//hash为0表示不是合法的头部
if(header[i].hash == ){
continue;
} //判断当前头部是否是“Rpc-Description”,如果想要忽略大小写,则应先用header[i].lowcase_key代替header[i].key.data,然后比较字符串。 if( == ngx_strncasecmp(header[i].key.data,
(u_char*) "Rpc-Description",
header[i].key.len))
{
//判断头部的值是否是“uploadFile”
if( == ngx_strncmp(header[i].key.data,
"uploadFile",
header[i].value.len))
{
//找到之后继续处理
}
}
}

获取headers的方法讲完了,下面是获取请求体(包体)的方法:

HTTP框架提供了一种方法可以异步接受包体:

ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler)

它的返回并不表示已经接受完成所有包体,只表示Nginx已经知道这个任务。所以一般返回为NGX_DONE(含义请自查,不赘述)。接受完所有包体之后,会调用post_handler函数指针指向的函数。其原型定义如下:

typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);

如果不想处理包体内容,可用如下方式将包体内容丢掉:

ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}

以上。欢迎留言讨论,联系方式:rwhsysu@163.com

 

Nginx重要结构request_t解析之http请求的获取的更多相关文章

  1. nginx源代码分析--配置文件解析

    ngx-conf-parsing 对 Nginx 配置文件的一些认识: 配置指令具有作用域,分为全局作用域和使用 {} 创建其他作用域. 同一作用域的不同的配置指令没有先后顺序:同一作用域能否使用同样 ...

  2. Nginx入门篇(二)之Nginx部署与配置文件解析

    一.Nginx编译安装 ()查看系统环境 [root@localhost tools]# cat /etc/redhat-release CentOS Linux release (Core) [ro ...

  3. nginx&http 第三章 ngx HTTP 请求的 11 个处理阶段

    nginx 将一个 HTTP 请求分为 11 个处理阶段,这样做让每一个 HTTP 模块可以仅仅专注于完成一个独立.简单的功能,而一个请求的完整处理过程可以由多个 HTTP 模块共同合作完成将一次 H ...

  4. nginx部分实现原理解析

    nginx底层实现有几个主要的模块: 进程模块 事件模块 网络模块 进程模块 默认采用守护模式启动,守护模式让master进程启动后在后台运行,不在窗口上卡住. Nginx 启动后会有一个 Maste ...

  5. LNP环境下Nginx与PHP配合解析的原理

    正在理解中,查阅资料,加上自我理解,得出如下结论,如有错误,欢迎指正.... LNP环境,Nginx与PHP配合运行的原理解释: 以前的互联网时代我们成为web1.0时代,那时用户是被动接受网络信息, ...

  6. nginx文件类型错误解析漏洞

    漏洞介绍:nginx是一款高性能的web服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持PHP的运行.80sec发现 其中存在一个较为严重的安全问题,默认情况下可能导致服务器错误的将 ...

  7. Nginx目录结构与配置文件详解

    Nginx安装 具体安装nginx请移步:[nginx部署] 安装依赖 安装pcre依赖软件 [root@ubuntu ~]# yum install -y pcre pcre-devel //外网情 ...

  8. 再提供一种解决Nginx文件类型错误解析漏洞的方法

    [文章作者:张宴 本文版本:v1.2 最后修改:2010.05.24 转载请注明原文链接:http://blog.zyan.cc/nginx_0day/] 注:2010年5月23日14:00前阅读本文 ...

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

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

随机推荐

  1. nginx server_参数配置总结(转)

    转:http://onlyzq.blog.51cto.com/1228/535279 Nginx中的server_name指令主要用于配置基于名称的虚拟主机,server_name指令在接到请求后的匹 ...

  2. Newtonsoft.Json.JsonWriter

    [一篮饭特稀原创,转载请注明出自http://www.cnblogs.com/wanghafan/p/4754769.html]  JsonWriter使用: 前台 $.post("Ajax ...

  3. wordpress的使用

    ubuntu 发送邮件学习资料: http://edu.51cto.com/lesson/id-6066.html 相关插件: Disable Google Fonts 使用中出现的问题: 1:wor ...

  4. servlet向ajax传递list数据类型,ajax向servlet传递array数据类型

    因工作需要, 1,后台向前台传递一个list 2,前台向后台传递类似于list的结构,但是因为javascript不支持list类型,所以只能使用二维数组代替 后台运行后的截图:           ...

  5. SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-012-AOP总结

    1.AOP是面向对象编程的有力补充,它可以让你把分散在应用中的公共辅助功能抽取成模块,以灵活配置,减少了重复代码,让类更关注于自身的功能

  6. 133. Clone Graph

    题目: Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. ...

  7. Android 各个版本WebView

    转载请注明出处   http://blog.csdn.net/typename/ powered by miechal zhao : miechalzhao@gmail.com 前言: 根据Googl ...

  8. RxJava开发精要4 – Observables过滤

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  9. 应付期间 Payables Periods

    (N) AP > Accounting > Control payables periods Click [Period Status] column to Open.

  10. bzoj1267 3784

    双倍经验题像这种方案太多不能全部求出来但求前k大一般有这样一个思路将所有方案无重复不漏的分为若干类,每个类的元素满足单调性,然后我们用堆维护就行了!对于这道题,可以想到用树的分治来处理路径,当处理根为 ...