Nginx 定義自己的 http 模塊

轉自:http://blog.csdn.net/u012243115/article/details/46898573

一、config文件編寫

        Nginx提供了一種簡單的方式將第三方的模塊編譯到Nginx。首先把源代碼文件全部放到一個目錄下,同時在該目錄中編寫一個文件用於通知Nginx如何編譯本模塊,這個文件名必須爲config。然後,在configure腳本執行時加入參數--add-module=PATH(新模塊源代碼以及config文件存放目錄),就可以在編譯Nginx之前把新模塊添加進去,然後再編譯(make)即可。

config文件格式

        config文件其實是一個可執行的Shell腳本,如果只想開發一個HTTP模塊,需要定義三個變量:

(1)ngx_adon_name

僅在configure執行時使用,一般設置爲模塊名稱。

(2)HTTP_MODULES

保存所有的HTTP模塊名稱。每個模塊間由空格相連。在重新設置這個變量時,不要直接覆蓋,因此要如下設置:

"$HTTP_MODULESngx_http_mytest_module"

(3)NGX_ADDON_SRCS

用於指定新模塊的源代碼,多個待編譯的源代碼之間可以用空格相連。

注意,在設置這個變量時可以使用$ngx_addon_dir變量,它等價於configure執行時--add-module=PATH的PATH參數。

本例中的config文件內容如下:

[cpp] view plain copy
  1. ngx_addon_name=ngx_http_mytest_module  
  2. HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"  
  3. NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"  

二、定義HTTP模塊及處理用戶請求

        用C語言編寫模塊源碼ngx_http_mytest_module.c。書中介紹了幾個數據結構和函數,經過梳理,它們的關係是這樣的:


        它們完成任務的具體過程和編碼實現原書上都有(一些數據傳遞如HTTP請求的解析、數據傳遞是由Nginx的HTTP框架完成的,在模塊代碼中並未體現),記得添加頭文件ngx_config.h、ngx_core.h和ngx_http.h:

ngx_http_mytest_module.c文件(與上面的config文件位於同一目錄下)如下:

源碼來源:http://nginx.weebly.com/31034203632830430721.html

[cpp] view plain copy
  1. #include <ngx_config.h>  
  2. #include <ngx_core.h>  
  3. #include <ngx_http.h>  
  4.   
  5.   
  6. static char *  
  7. ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);  
  8.   
  9. static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);  
  10.   
  11.   
  12. //處理配置項    
  13. static ngx_command_t  ngx_http_mytest_commands[] =  
  14. {  
  15.   
  16.     {  
  17.         ngx_string("mytest"),  
  18.         NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,  
  19.         ngx_http_mytest,  
  20.         NGX_HTTP_LOC_CONF_OFFSET,  
  21.         0,  
  22.         NULL  
  23.     },  
  24.   
  25.     ngx_null_command  
  26. };  
  27. //模塊上下文  
  28. static ngx_http_module_t  ngx_http_mytest_module_ctx =  
  29. {  
  30.     NULL,                              /* preconfiguration */  
  31.     NULL,                       /* postconfiguration */  
  32.   
  33.     NULL,                              /* create main configuration */  
  34.     NULL,                              /* init main configuration */  
  35.   
  36.     NULL,                              /* create server configuration */  
  37.     NULL,                              /* merge server configuration */  
  38.   
  39.     NULL,                   /* create location configuration */  
  40.     NULL                    /* merge location configuration */  
  41. };  
  42. //新模塊定義    
  43. ngx_module_t  ngx_http_mytest_module =  
  44. {  
  45.     NGX_MODULE_V1,  
  46.     &ngx_http_mytest_module_ctx,           /* module context */  
  47.     ngx_http_mytest_commands,              /* module directives */  
  48.     NGX_HTTP_MODULE,                       /* module type */  
  49.     NULL,                                  /* init master */  
  50.     NULL,                                  /* init module */  
  51.     NULL,                                  /* init process */  
  52.     NULL,                                  /* init thread */  
  53.     NULL,                                  /* exit thread */  
  54.     NULL,                                  /* exit process */  
  55.     NULL,                                  /* exit master */  
  56.     NGX_MODULE_V1_PADDING  
  57. };  
  58.   
  59. //配置項對應的回調函數   
  60. static char *  
  61. ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)  
  62. {  
  63.     ngx_http_core_loc_conf_t  *clcf;  
  64.   
  65.     //首先找到mytest配置項所屬的配置塊,clcf貌似是location塊內的數據  
  66. //結構,其實不然,它可以是main、srv或者loc級別配置項,也就是說在每個  
  67. //http{}和server{}內也都有一個ngx_http_core_loc_conf_t結構體  
  68.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);  
  69.   
  70.     //http框架在處理用戶請求進行到NGX_HTTP_CONTENT_PHASE階段時,如果  
  71. //請求的主機域名、URI與mytest配置項所在的配置塊相匹配,就將調用我們  
  72. //實現的ngx_http_mytest_handler方法處理這個請求  
  73.     clcf->handler = ngx_http_mytest_handler;  
  74.   
  75.     return NGX_CONF_OK;  
  76. }  
  77.   
  78. //實際完成處理的回調函數    
  79. static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)  
  80. {  
  81.     //必須是GET或者HEAD方法,否則返回405 Not Allowed  
  82.     if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))  
  83.     {  
  84.         return NGX_HTTP_NOT_ALLOWED;  
  85.     }  
  86.   
  87.     //丟棄請求中的包體  
  88.     ngx_int_t rc = ngx_http_discard_request_body(r);  
  89.     if (rc != NGX_OK)  
  90.     {  
  91.         return rc;  
  92.     }  
  93.   
  94.     //設置返回的Content-Type。注意,ngx_str_t有一個很方便的初始化宏  
  95. //ngx_string,它可以把ngx_str_t的data和len成員都設置好  
  96.     ngx_str_t type = ngx_string("text/plain");  
  97.     //返回的包體內容  
  98.     ngx_str_t response = ngx_string("Hello World!");  
  99.     //設置返回狀態碼  
  100.     r->headers_out.status = NGX_HTTP_OK;  
  101.     //響應包是有包體內容的,所以需要設置Content-Length長度  
  102.     r->headers_out.content_length_n = response.len;  
  103.     //設置Content-Type  
  104.     r->headers_out.content_type = type;  
  105.   
  106.     //發送http頭部  
  107.     rc = ngx_http_send_header(r);  
  108.     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)  
  109.     {  
  110.         return rc;  
  111.     }  
  112.   
  113.     //構造ngx_buf_t結構準備發送包體  
  114.     ngx_buf_t                 *b;  
  115.     b = ngx_create_temp_buf(r->pool, response.len);  
  116.     if (b == NULL)  
  117.     {  
  118.         return NGX_HTTP_INTERNAL_SERVER_ERROR;  
  119.     }  
  120.     //將Hello World拷貝到ngx_buf_t指向的內存中  
  121.     ngx_memcpy(b->pos, response.data, response.len);  
  122.     //注意,一定要設置好last指針  
  123.     b->last = b->pos + response.len;  
  124.     //聲明這是最後一塊緩衝區  
  125.     b->last_buf = 1;  
  126.   
  127.     //構造發送時的ngx_chain_t結構體  
  128.     ngx_chain_t     out;  
  129.     //賦值ngx_buf_t  
  130.     out.buf = b;  
  131.     //設置next爲NULL  
  132.     out.next = NULL;  
  133.   
  134.     //最後一步發送包體,http框架會調用ngx_http_finalize_request方法  
  135. //結束請求  
  136.     return ngx_http_output_filter(r, &out);  
  137. }  


三、修改配置文件 

        最後一步是修改nginx.conf配置,爲http塊中增加一個對應於mytest模塊的location塊:

[cpp] view plain copy
  1. location /test {  
  2.         mytest;  
  3. }  

如下圖所示:


四、編譯安裝新模塊

        重新編譯Nginx源碼使其包含新定義的模塊(注需要把以前安裝的刪掉):


[cpp] view plain copy
  1. ./configure  --add-module=/home/nginx(這個路徑是上面的conf和ngx_http_mytest_module.c文件所在的路徑)  
  2. make  
  3. make install  

五、驗證結果

        安裝好Nginx之後,打開服務器:/usr/local/nginx/sbin/nginx 

        然後在瀏覽器輸入:http://localhost/test即可看到Hello World字樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章