日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Nginx >内容正文

Nginx

Nginx重要结构request_t解析之http请求的获取

發布時間:2024/2/28 Nginx 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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请求的获取的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。