1. 程式人生 > >Nginx入門之兩種handler函式的掛載方式

Nginx入門之兩種handler函式的掛載方式

請在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。

接著上次的文章,今天研究《深入理解Nginx模組開發與架構解析》一書中給出的mytest的例子,發現和 /tengine.taobao.org/book/ 一書中的例子不甚相同,尤其是在handler函式的掛在方面。

函式的掛載分為兩種方式:

一種方式就是按處理階段掛載;另外一種掛載方式就是按需掛載。tengine.taobao.org 中使用的掛載方式是按處理階段掛載,而深入理解一書中的掛載方式是按需求掛載。

首先看/tengine.taobao.org/book/中的例子:

由我之前 Nginx_handler模組發開(hello模組結構解析)

一文,handler_init就是handler函式的掛載函式,該函式在上下文結構中的postconfiguration欄位被呼叫,決定handler函式在哪裡被掛載。

複製程式碼

複製程式碼

 1 static ngx_http_module_t ngx_http_hello_module_ctx = {
 2         NULL,                          /* preconfiguration */
 3         ngx_http_hello_init,           /* postconfiguration */
 4 
 5         NULL,                          /* create main configuration */
 6         NULL,                          /* init main configuration */
 7 
 8         NULL,                          /* create server configuration */
 9         NULL,                          /* merge server configuration */
10 
11         ngx_http_hello_create_loc_conf, /* create location configuration */
12         NUL

複製程式碼

複製程式碼

 

複製程式碼

複製程式碼

 1 static ngx_int_t
 2 ngx_http_hello_init(ngx_conf_t *cf)
 3 {
 4         ngx_http_handler_pt        *h;
 5         ngx_http_core_main_conf_t  *cmcf;
 6 
 7         cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); //取得core_module的cf
 8 
 9         h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); // 掛載函式到對應處理階段
10         if (h == NULL) {
11                 return NGX_ERROR;
12         }
13 
14         *h = ngx_http_hello_handler; //將函式指標指向handler函式
15 
16         return NGX_OK;
17 }

複製程式碼

複製程式碼

使用這種方式掛載的handler也被稱為 content phase handlers

 

 

而在《深入理解Nginx模組開發與架構解析》一書中給出的mytest的例子中,則是按需求掛載:

以這種方式掛載的handler也被稱為 content handler

當一個請求進來以後,nginx從NGX_HTTP_POST_READ_PHASE階段開始依次執行每個階段中所有handler。執行到 NGX_HTTP_CONTENT_PHASE階段的時候,如果這個location有一個對應的content handler模組,那麼就去執行這個content handler模組真正的處理函式。否則繼續依次執行NGX_HTTP_CONTENT_PHASE階段中所有content phase handlers,直到某個函式處理返回NGX_OK或者NGX_ERROR。

換句話說,當某個location處理到NGX_HTTP_CONTENT_PHASE階段時,如果有content handler模組,那麼NGX_HTTP_CONTENT_PHASE掛載的所有content phase handlers都不會被執行了。

但是使用這個方法掛載上去的handler有一個特點是必須在NGX_HTTP_CONTENT_PHASE階段才能執行到。如果你想自己的handler在更早的階段執行,那就不要使用這種掛載方式。

那麼在什麼情況會使用這種方式來掛載呢?一般情況下,某個模組對某個location進行了處理以後,發現符合自己處理的邏輯,而且也沒有必要再呼叫NGX_HTTP_CONTENT_PHASE階段的其它handler進行處理的時候,就動態掛載上這個handler。

mytest這個例子在配置結構中,直接呼叫了content handler函式,名為ngx_http_mytest,該函式直接實現了真正的handler函式的掛載執行:

複製程式碼

複製程式碼

 1 static ngx_command_t ngx_http_mytest_commands[] = {
 2     {
 3         ngx_string("mytest"),
 4         NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
 5         ngx_http_mytest,
 6         NGX_HTTP_LOC_CONF_OFFSET,
 7         0,
 8         NULL
 9     },
10     ngx_null_command
11 };

複製程式碼

複製程式碼

content handler函式 ngx_http_mytest的定義如下:

複製程式碼

複製程式碼

 1 static char * 
 2 ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 3 {
 4     ngx_http_core_loc_conf_t *clcf;
 5 
 6     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 7 
 8     clcf->handler = ngx_http_mytest_handler;
 9 
10     return NGX_CONF_OK;
11 }

複製程式碼

複製程式碼

定義十分簡單,主要就是一個ngx_http_conf_get_module_loc_conf函式的呼叫,以及一個函式指標的賦值。函式指標的賦值實現了真正的handler函式的掛載。

那麼,我們來看看被呼叫的ngx_http_conf_get_module_loc_con函式的定義:

#define ngx_http_conf_get_module_loc_conf(cf, module)                         \
    ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]

只是一個巨集定義,主要作用是將之前儲存起來的conf內容調出,賦值給clcf。

聯絡方式:[email protected]