Nginx重要结构request_t解析之http请求的获取
本文主要参考为《深入理解nginx模块开发与架构解析》一书,处理用户请求部分,是一篇包含作者理解的读书笔记。欢迎指正,讨论。
handler函数的定义模型如下:
1 static ngx_int_t
2 ngx_http_hello_handler(ngx_http_request_t *r)
3 {}
请求的所有信息都可以在传入的ngx_http_request_t类型指针参数 r 中获得。Ngx_http_request_t结构体包含的内容很多,这里只讨论其中获取HTTP请求的部分,相关定义如下:
1 struct ngx_http_request_s {2 ...3 //请求头4 ngx_buf_t *header_in;5 6 ngx_http_headers_in_t headers_in;7 ngx_http_headers_out_t headers_out;8 //请求体9 ngx_http_request_body_t *request_body;
10 //请求行
11 ngx_uint_t method;
12 ngx_uint_t http_version;
13
14 ngx_str_t request_line;
15 ngx_str_t uri;
16 ngx_str_t args;
17 ngx_str_t exten;
18 ngx_str_t unparsed_uri;
19
20 ngx_str_t method_name;
21 ngx_str_t http_protocol;
22 ...
23 /*
24 * a memory that can be reused after parsing a request line
25 * via ngx_http_ephemeral_t
26 */
27
28 u_char *uri_start;
29 u_char *uri_end;
30 u_char *uri_ext;
31 u_char *args_start;
32 u_char *request_start;
33 u_char *request_end;
34 u_char *method_end;
35 u_char *schema_start;
36 u_char *schema_end;
37 u_char *host_start;
38 u_char *host_end;
39 u_char *port_start;
40 u_char *port_end;
41 ...
42 };
相关定义全在上面列出,
下面,我们先从请求行的获取来解释:
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头部。结构体定义如下:
1 typedef struct {2 ngx_list_t headers;3 4 ngx_table_elt_t *host;5 ngx_table_elt_t *connection;6 ngx_table_elt_t *if_modified_since;7 ngx_table_elt_t *if_unmodified_since;8 ngx_table_elt_t *if_match;9 ngx_table_elt_t *if_none_match;
10 ngx_table_elt_t *user_agent;
11 ngx_table_elt_t *referer;
12 ngx_table_elt_t *content_length;
13 ngx_table_elt_t *content_type;
14
15 ngx_table_elt_t *range;
16 ngx_table_elt_t *if_range;
17
18 ngx_table_elt_t *transfer_encoding;
19 ngx_table_elt_t *expect;
20 ngx_table_elt_t *upgrade;
21
22 #if (NGX_HTTP_GZIP)
23 ngx_table_elt_t *accept_encoding;
24 ngx_table_elt_t *via;
25 #endif
26
27 ngx_table_elt_t *authorization;
28
29 ngx_table_elt_t *keep_alive;
30
31 #if (NGX_HTTP_X_FORWARDED_FOR)
32 ngx_array_t x_forwarded_for;
33 #endif
34
35 #if (NGX_HTTP_REALIP)
36 ngx_table_elt_t *x_real_ip;
37 #endif
38
39 #if (NGX_HTTP_HEADERS)
40 ngx_table_elt_t *accept;
41 ngx_table_elt_t *accept_language;
42 #endif
43
44 #if (NGX_HTTP_DAV)
45 ngx_table_elt_t *depth;
46 ngx_table_elt_t *destination;
47 ngx_table_elt_t *overwrite;
48 ngx_table_elt_t *date;
49 #endif
50
51 ngx_str_t user;
52 ngx_str_t passwd;
53
54 ngx_array_t cookies;
55
56 ngx_str_t server;
57 off_t content_length_n;
58 time_t keep_alive_n;
59
60 unsigned connection_type:2;
61 unsigned chunked:1;
62 unsigned msie:1;
63 unsigned msie6:1;
64 unsigned opera:1;
65 unsigned gecko:1;
66 unsigned chrome:1;
67 unsigned safari:1;
68 unsigned konqueror:1;
69 } 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 = 0;/*void*/;i++){//判断是否到达链表中当前数组结尾if(i>=part->nelts){//是否还有下一个链表数组元素if(part->next == NULL){break;}//part设置为next来访问下一个链表数组;header也指向下一个链表数组的首地址,设置i为0,表示从头开始遍历新的链表数组。part = part->next;header = part->elts;i=0;}//hash为0表示不是合法的头部if(header[i].hash == 0){continue;}//判断当前头部是否是“Rpc-Description”,如果想要忽略大小写,则应先用header[i].lowcase_key代替header[i].key.data,然后比较字符串。if(0 == ngx_strncasecmp(header[i].key.data,(u_char*) "Rpc-Description",header[i].key.len)){//判断头部的值是否是“uploadFile”if(0 == 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;}
Nginx重要结构request_t解析之http请求的获取相关推荐
- Nginx的核心原理解析
Nginx 反向代理VS正向代理: 反向代理服务器对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置.客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向 ...
- nginx部分实现原理解析
nginx底层实现有几个主要的模块: 进程模块 事件模块 网络模块 进程模块 默认采用守护模式启动,守护模式让master进程启动后在后台运行,不在窗口上卡住. Nginx 启动后会有一个 Maste ...
- nginx html解析插件,nginx配置信息的解析流程
nginx配置信息的解析流程 2011年9月9日 1,744 次浏览 请关注最新修正合订: 这一系列的文章还是在09年写的,存在电脑里很久了,现在贴出来.顺序也不记得了,看到那个就发那个吧,最近都会发 ...
- nginx文件类型错误解析漏洞
漏洞介绍:nginx是一款高性能的web服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持PHP的运行.80sec发现其中存在一个较为严重的安全问题,默认情况下可能导致服务器错误的将任 ...
- get请求可以传body吗_详解用 Go 语言解析各种 HTTP 请求的方法
之前这个系列的文章一直在讲用 Go 语言怎么编写HTTP服务器来提供服务,如何给服务器配置路由来匹配请求到对应的处理程序,如何添加中间件把一些通用的处理任务从具体的Handler中解耦出来,以及如何更 ...
- Nginx 反向代理可以缓存 HTTP POST 请求页面吗?
2019独角兽企业重金招聘Python工程师标准>>> Nginx 反向代理可以缓存 HTTP POST 请求页面吗? 2017-09-05 景峯 Netkiller 本文节选自&l ...
- Nginx目录结构、编译参数、状态码概述
文章目录 Nginx目录结构 Nginx编译参数 Nginx模块 Nginx内置变量 Nginx状态码 Nginx目录结构 路径 类型 /etc/nginx /etc/nginx/nginx.conf ...
- Volley 源码解析之图片请求
一.前言 上篇文章我们分析了网络请求,这篇文章分析对图片的处理操作,如果没看上一篇,可以先看上一篇文章Volley 源码解析之网络请求.Volley 不仅仅对请求网络数据作了良好的封装,还封装了对图片 ...
- Nginx 解决WebApi跨域二次请求以及Vue单页面问题
Nginx 解决WebApi跨域二次请求以及Vue单页面问题 参考文章: (1)Nginx 解决WebApi跨域二次请求以及Vue单页面问题 (2)https://www.cnblogs.com/ji ...
最新文章
- 3. SQL -- 存储过程
- iOS之百度导航SDK的坐标转换
- 什么是Mac上的JDK路径? [重复]
- 线性代数学习笔记(十一)
- 如何给SAP云平台购买的账号分配Process Integration服务
- 云原生开发框架dapr环境搭建:CLI安装和初始化
- WP7开发小技巧之快捷键
- python 内存分析工具_[转] python运行时内存分析工具meliae
- 陕师大计算机科学学院研究生,陕师大研究生
- PS使用:解决图片使用PS打开提示无法完成请求,因为找到不知名的或无效的JPEG标志符类型
- WebStorm中配置node.js(Windows)
- 【优化算法】材料生成算法 (MGA)【含Matlab源码 209期】
- Linux的基础操作
- verilog的描述风格
- 树莓派pico--PIO入门
- VM虚拟机设置桥接模式
- JAVA服务器获取手机设备的IP地址
- linux 命令修改IP(最有效方法)
- 有利可图网_有利可图的项目的目录
- UVM学习笔记(一)工厂、phase机制、config
热门文章
- 初学Android,字符串,数字,尺寸,数组资源(十二)
- sp_updatestats和update statistics的区别
- HDU - 6406 Taotao Picks Apples(线段树区间合并)
- POJ - 3422 Kaka's Matrix Travels(网络流-最大费用最大流+拆点法)
- HDU - 5877 Weak Pair(离散化+树状数组+dfs序)
- 剑指 Offer II 014. 字符串中的变位词
- 16.枚举中的option和result.rs
- Windows 服务(附服务开发辅助工具)
- 几个预编译指令的用法
- 分布式系统概念 | 分布式ID:数据库、号段模式、雪花算法(Snowflake)、Redis实现方案