3.6.2 获取URI和参数

请求的所有信息(如方法、URI、协议版本号和头部等)都可以在传入的ngx_http_request_t类型参数r中取得。ngx_http_request_t结构体的内容很多,本节不会探讨ngx_http_request_t中所有成员的意义(ngx_http_request_t结构体中的许多成员只有HTTP框架才感兴趣,在11.3.1节会更详细的说明),只介绍一下获取URI和参数的方法,这非常简单,因为Nginx提供了多种方法得到这些信息。下面先介绍相关成员的定义。


typedef struct ngx_http_request_s

ngx_http_request_t;

struct ngx_http_request_s{

……

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;

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;

……

};


在对一个用户请求行进行解析时,可以得到下列4类信息。

(1)方法名

method的类型是ngx_uint_t(无符号整型),它是Nginx忽略大小写等情形时解析完用户请求后得到的方法类型,其取值范围如下所示。


define NGX_HTTP_UNKNOWN

0x0001

define NGX_HTTP_GET

0x0002

define NGX_HTTP_HEAD

0x0004

define NGX_HTTP_POST

0x0008

define NGX_HTTP_PUT

0x0010

define NGX_HTTP_DELETE

0x0020

define NGX_HTTP_MKCOL

0x0040

define NGX_HTTP_COPY

0x0080

define NGX_HTTP_MOVE

0x0100

define NGX_HTTP_OPTIONS

0x0200

define NGX_HTTP_PROPFIND

0x0400

define NGX_HTTP_PROPPATCH

0x0800

define NGX_HTTP_LOCK

0x1000

define NGX_HTTP_UNLOCK

0x2000

define NGX_HTTP_TRACE

0x4000


当需要了解用户请求中的HTTP方法时,应该使用r->method这个整型成员与以上15个宏进行比较,这样速度是最快的(如果使用method_name成员与字符串做比较,那么效率会差很多),大部分情况下推荐使用这种方式。除此之外,还可以用method_name取得用户请求中的方法名字符串,或者联合request_start与method_end指针取得方法名。method_name是ngx_str_t类型,按照3.2.2节中介绍的方法使用即可。

request_start与method_end的用法也很简单,其中request_start指向用户请求的首地址,同时也是方法名的地址,method_end指向方法名的最后一个字符(注意,这点与其他xxx_end指针不同)。获取方法名时可以从request_start开始向后遍历,直到地址与method_end相同为止,这段内存存储着方法名。

注意 Nginx中对内存的控制相当严格,为了避免不必要的内存开销,许多需要用到的成员都不是重新分配内存后存储的,而是直接指向用户请求中的相应地址。例如,method_name.data、request_start这两个指针实际指向的都是同一个地址。而且,因为它们是简单的内存指针,不是指向字符串的指针,所以,在大部分情况下,都不能将这些u_char*指针当做字符串使用。

(2)URI

ngx_str_t类型的uri成员指向用户请求中的URI。同理,u_char类型的uri_start和uri_end也与request_start、method_end的用法相似,唯一不同的是,method_end指向方法名的最后一个字符,而uri_end指向URI结束后的下一个地址,也就是最后一个字符的下一个字符地址(HTTP框架的行为),这是大部分u_char类型指针对"xxx_start"和"xxx_end"变量的用法。

ngx_str_t类型的extern成员指向用户请求的文件扩展名。例如,在访问"GET/a.txt HTTP/1.1"时,extern的值是{len=3,data="txt"},而在访问"GET/a HTTP/1.1"时,extern的值为空,也就是{len=0,data=0x0}。

uri_ext指针指向的地址与extern.data相同。

unparsed_uri表示没有进行URL解码的原始请求。例如,当uri为"/a b"时,unparsed_uri是"/a%20b"(空格字符做完编码后是%20)。

(3)URL参数

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

args_start指向URL参数的起始地址,配合uri_end使用也可以获得URL参数。

(4)协议版本

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可以获取原始的用户请求行。