nginx處理http
ngx_http_read_client_request_body
HTTP包體的長度有可能非常大,如果試圖一次性呼叫並讀取完所有的包體,那麼多半會阻塞Nginx程序。HTTP框架提供了一種方法來非同步地接收包體:
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler);ngx_http_read_client_request_body是一個非同步方法,呼叫它只是說明要求Nginx開始接收請求的包體,並不表示是否已經接收完,當接收完所有的包體內容後,post_handler指向的回撥方法會被呼叫。因此,即使在呼叫了ngx_http_read_client_request_body方法後它已經返回,也無法確定這時是否已經呼叫過post_handler指向的方法。換句話說,ngx_http_read_client_request_body返回時既有可能已經接收完請求中所有的包體(假如包體的長度很小),也有可能還沒開始接收包體。如果ngx_http_read_client_request_body是在ngx_http_mytest_handler處理方法中呼叫的,那麼後者一般要返回NGX_DONE,因為下一步就是將它的返回值作為引數傳給ngx_http_finalize_request。NGX_DONE的意義如下:
NGX_DONE:表示到此為止,同時HTTP框架將暫時不再繼續執行這個請求的後續部分。事實上,這時會檢查連線的型別,如果是keepalive型別的使用者請求,就會保持住HTTP連線,然後把控制權交給Nginx。這個返回碼很有用,考慮以下場景:在一個請求中我們必須訪問一個耗時極長的操作(比如某個網路呼叫),這樣會阻塞住Nginx,又因為我們沒有把控制權交還給Nginx,而是在ngx_http_mytest_handler中讓Nginx worker程序休眠了(如等待網路的回包),所以,這就會導致Nginx出現效能問題,該程序上的其他使用者請求也得不到響應。可如果我們把這個耗時極長的操作分為上下兩個部分(就像Linux核心中對中斷處理的劃分),上半部分和下半部分都是無阻塞的(耗時很少的操作),這樣,在ngx_http_mytest_handler進入時呼叫上半部分,然後返回NGX_DONE,把控制交還給Nginx,從而讓Nginx繼續處理其他請求。在下半部分被觸發時(這裡不探討具體的實現方式,事實上使用upstream方式做反向代理時用的就是這種思想),再回調下半部分處理方法,這樣就可以保證Nginx的高效能特性了。如果需要徹底瞭解NGX_DONE的意義,那麼必須學習第11章內容,其中還涉及請求的引用計數內容。
下面看一下包體接收完畢後的回撥方法原型ngx_http_client_body_handler_pt是如何定義的:
typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);
其中,有引數ngx_http_request_t *r,這個請求的資訊都可以從r中獲得。這樣可以定義一個方法void func(ngx_http_request_t *r),在Nginx接收完包體時呼叫它,另外,後續的流程也都會寫在這個方法中,例如:
void ngx_http_mytest_body_handler(ngx_http_request_t *r)
{
…
}
注意 ngx_http_mytest_body_handler的返回型別是void,Nginx不會根據返回值做一些收尾工作,因此,我們在該方法裡處理完請求時必須要主動呼叫ngx_http_finalize_request方法來結束請求。
接收包體時可以這樣寫:
ngx_int_t rc = ngx_http_read_client_request_body(r, ngx_http_mytest_body_handler);
if (rc >= NGX_http_SPECIAL_RESPONSE) {
return rc;
}
return NGX_DONE;
Nginx非同步接收HTTP請求的包體的內容將在11.8節中詳述。
如果不想處理請求中的包體,那麼可以呼叫ngx_http_discard_request_body方法將接收自客戶端的HTTP包體丟棄掉。例如:
ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
ngx_http_discard_request_body只是丟棄包體,不處理包體不就行了嗎?何必還要呼叫ngx_http_discard_request_body方法呢?其實這一步非常有意義,因為有些客戶端可能會一直試圖傳送包體,而如果HTTP模組不接收發來的TCP流,有可能造成客戶端傳送超時。
接收完請求的包體後,可以在r->request_body->temp_file->file中獲取臨時檔案(假定將r->request_body_in_file_only標誌位設為1,那就一定可以在這個變數獲取到包體。更復雜的接收包體的方式本節暫不討論)。file是一個ngx_file_t型別。這裡,我們可以從r->request_body->temp_file->file.name中獲取Nginx接收到的請求包體所在檔案的名稱(包括路徑)。
返回值的意義
每個階段都有一個與之相關的handler的列表。一旦把handler註冊到對應的階段,那麼handler就會返回某個下面的值:
NGX_OK:請求已經成功處理,請求將會傳到下一個階段。
NGX_DECLINED:請求需要被轉發到本階段的下一個handler
NGX_AGAIN,NGX_DONE:請求已經被正確處理,同時請求被掛起,直到某個事件(子請求結束、socket可寫或超時等)到來,handler才會再次被呼叫。
//函式功能:解析請求行。
static void ngx_http_process_request_line(ngx_event_t *rev)
{
。。。
rc = NGX_AGAIN;
for ( ;; ) {
if (rc == NGX_AGAIN) { // NO.1
n = ngx_http_read_request_header(r);
//recv()讀取請求頭資訊
if (n == NGX_AGAIN || n == NGX_ERROR) {
return;
}
}
//記錄請求行中的請求方法(Method),請求uri以及http協議版本在緩衝區中的起始位置
rc = ngx_http_parse_request_line(r, r->header_in);
if (rc == NGX_OK) {
…
c->log->action = "reading client request headers";
rev->handler = ngx_http_process_request_headers;
ngx_http_process_request_headers(rev);
return;
}
。。。
}
}
//函式功能:處理HTTP請求頭。
static void ngx_http_process_request_headers(ngx_event_t *rev)
{
。。。
if (rev->timedout) { // 是否超時
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
。。。
rc = NGX_AGAIN;
for ( ;; ) {
if (rc == NGX_AGAIN) {
if (r->header_in->pos == r->header_in->end) { //一般不需要
rv = ngx_http_alloc_large_header_buffer(r, 0);
。。。
}
n = ngx_http_read_request_header(r); //快速返回了,因為已經讀過
if (n == NGX_AGAIN || n == NGX_ERROR) {
return;
}
}
rc = ngx_http_parse_header_line(r, r->header_in,
cscf->underscores_in_headers); //解析HTTP頭部
if (rc == NGX_OK) {
if (r->invalid_header && cscf->ignore_invalid_headers) {
。。。
//以key 和value的格式儲存HTTP頭
h = ngx_list_push(&r->headers_in.headers); //ngx_http_headers_in_t ,存放key,value
if (h == NULL) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
h->hash = r->header_hash;
h->key.len = r->header_name_end - r->header_name_start;
h->key.data = r->header_name_start; // "User-Agent",host
h->key.data[h->key.len] = '\0';
h->value.len = r->header_end - r->header_start;
h->value.data = r->header_start;
。。。
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { //檢驗函式
return;
}
continue;
}
if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http header done");
r->request_length += r->header_in->pos - r->header_in->start;
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
rc = ngx_http_process_request_header(r); //檢驗頭資訊如1.1協議需要host資訊?
if (rc != NGX_OK) {
return;
}
ngx_http_process_request(r);
return;
}
。。。。
}
}
//函式功能:處理請求。
static voidngx_http_process_request(ngx_http_request_t *r)
{
。。。
if (c->read->timer_set) { // 超時,過了一會兒,就在這裡了
ngx_del_timer(c->read); //here
}
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;
r->read_event_handler = ngx_http_block_reading;
ngx_http_handler(r); //核心是ngx_http_core_run_phases,進入各階段處理函式
ngx_http_run_posted_requests(c);
}
相關推薦
nginx處理http(http變數篇)
nginx http變數定義 struct ngx_http_variable_s { ngx_str_t name; &nbs
nginx處理http
ngx_http_read_client_request_body HTTP包體的長度有可能非常大,如果試圖一次性呼叫並讀取完所有的包體,那麼多半會阻塞Nginx程序。HTTP框架提供了一種方法來非同步地接收包體: ngx_int_t ngx_http_re
nginx處理http(http處理結構篇)
http頭部結構定義 頭部處理函式指標定義 /* @param r http請求結構 @param h http頭部的hash表 @param offset 位於結構體中的偏移量 */ typedef ngx_int_t (*ngx_http_heade
萬字長文!一次性弄懂 Nginx 處理 HTTP 請求的 11 個階段
# Nginx 處理一個 HTTP 請求的全過程 前面給大家講了 [Nginx 是如何處理 HTTP請求頭部的](https://iziyang.github.io/2020/04/08/4-nginx/),接下來就到了真正處理 HTTP 請求的階段了。先看下面這張圖,這張圖是 Nginx 處理 HTTP
Nginx的 HTTP 499 狀態碼處理
搜索 是什麽 src 多個 客戶端連接 alt nec logs 源碼 1、前言 今天在處理一個客戶問題,遇到Nginx access log中出現大量的499狀態碼。實際場景是:客戶的域名通過cname解析到我們的Nginx反向代理集群上來,客戶的Web服務是由一個
nginx丟棄http包體處理
length 如果 等於 sina 函數 文件 清0 能夠 request http框架丟棄http請求包體和上一篇文章http框架接收包體, 都是由http框架提供的兩個方法,供http各個模塊調用,從而決定對包體做什麽處理。是選擇丟棄還是接收,都是由模塊決定的。例如靜
【Nginx】HTTP請求的11個處理階段
Nginx將一個HTTP請求分成多個階段。以模組為單位進行處理。這樣做的優點是使處理過程更加靈活、減少耦合度。HTTP框架將處理分成了11個階段,各個階段能夠包括隨意多個HTTP模組並以流水線的方式處理請求。這11個HTTP階段例如以下所看到的:
nginx系列7:處理HTTP請求的11個階段
處理HTTP請求的11個階段 如下圖: 序號 階段 指令 備註 1 POST_READ realip 獲取客戶端真實IP 2 SERVER_REWRITE rewrite
菜鳥學習nginx之HTTP請求處理(1)
上一篇主要介紹Nginx是如何處理HTTP Header。由於HTTP請求處理這部分程式碼是Nginx核心內容,打算用兩篇文章深入介紹。本篇先介紹HTTP處理的11個階段。 一、HTTP處理11階段 1.1、為什麼要有11階段? 這個得從Nginx設計出發。首先Nginx是單執行緒且
Nginx 中處理 HTTP 請求
概述 在 Nginx 的初始化啟動過程中,worker 工作程序會呼叫事件模組的ngx_event_process_init 方法為每個監聽套接字ngx_listening_t 分配一個 ngx_connection_t 連線,並設定該連線上讀事件的
nginx處理post請求(http響應頭部的收發)
上一篇文章分析了nginx如何傳送來自客戶端的請求資料到後端伺服器, 本篇文章開始將分析nginx如何接收來自後端伺服器的響應。nginx接收來自後端伺服器的響應分為兩個過程,一個是接收來自後端伺服器的http響應頭部, 另一個是接收來自後端伺服器的響應包體
NGINX中HTTP請求的11個處理階段
Nginx的模組化設計使得每一個HTTP模組可以僅專注於完成一個獨立的、簡單的功能,而一個請求的完整處理過程可以由無數個HTTP模組共同合作完成。這種設計有非常好的簡單性、可測試性、可擴充套件性,然而,當多個http模組流水式地處理同一個請求時,單一的處理順序是無法滿足靈
優化 Nginx 處理事件模型
標準 root 高效 nginx pre conf icop con div Nginx 的連接處理機制在不同的操作系統會采用不同的 I/O 模型,要根據不同的系統選擇不同的事件處理模型,可供選擇的事件處理模型有:kqueue 、rtsig 、epoll 、/dev/pol
(二)servlet處理Http響應
web nbsp 購物車 res 請求 head 自動 地址 發生 重定向:web服務器收到客戶端的請求後,通知客戶端發送一個新的請求到另一個房web服務器。 resp.sendRedirect("URL"); 特點:1)客戶端發送兩次請求 2)瀏
Serlvet 處理http請求並保持長連接
數據 http print htm boa out eth 3.0 cte 一.Servlet,一個請求在容器中是如何處理的 Servlet規定的,相應客戶請求訪問特定Servlet流程如下: 1.客戶端發出請求。 2.Servlet容器接收客戶請求解析。 3.Se
nginx配置http跳轉https
文件 簡單 div 文件頭部 配置 gin list ... 需要 配置相當簡單,在配置文件頭部加一行,如下: server { listen *:80;//監聽80端口 return 301 htt
(轉)關於Tomcat的點點滴滴(體系架構、處理http請求的過程、安裝和配置、目錄結構、設置壓縮和對中文文件名的支持、以及Catalina這個名字的由來……等)
https 設置 重啟 specific 調用 持久化數據 所在 original apps 轉自:http://itfish.net/article/41668.html 總結Tomcat的體系架構、處理http請求的過程、安裝和配置、目錄結構、設置壓縮和對中文文件名
Nginx 之 http配置段介紹
ngx_http_core_module1 概述本文將介紹nginx裏http配置段的相關配置,主要介紹ngx_http_core_module這個模塊的相關功能和命令。由於主配置文件的http配置段裏有 include /etc/nginx/conf.d/*.conf; 這個配置,因此可以單獨在路徑/et
java處理HTTP請求
connect implement turn set readline catch append 內容 nco 1 import com.diyfintech.wx.service.HttpService; 2 import org.springframework.s
Spring MVC 處理HTTP請求的整體流程
含義 alt myba 解析 patch ros ati 框架 ice DispatcherServlet是一個前端控制器,是整個Spring MVC框架的核心組件。它在接收HTTP請求之後,根據請求調用Spring MVC中的各個組件。 常用接口及其含義: 1